/* * SelectionLayer::render * * Renders the group color highlight behind the active tab using cairo * */ void SelectionLayer::render () { cairo_t *cr; if (!HAS_TOP_WIN (mGroup) || !mCairo) return; cr = mCairo; /* fill */ cairo_set_line_width (cr, 2); cairo_set_source_rgba (cr, (mGroup->mColor[0] / 65535.0f), (mGroup->mColor[1] / 65535.0f), (mGroup->mColor[2] / 65535.0f), (mGroup->mColor[3] / (65535.0f * 2))); cairo_move_to (cr, 0, 0); cairo_rectangle (cr, 0, 0, width (), height ()); cairo_fill_preserve (cr); /* outline */ cairo_set_source_rgba (cr, (mGroup->mColor[0] / 65535.0f), (mGroup->mColor[1] / 65535.0f), (mGroup->mColor[2] / 65535.0f), (mGroup->mColor[3] / 65535.0f)); cairo_stroke (cr); mTexture = GLTexture::imageBufferToTexture ((char*) mBuffer, (CompSize &) *this); }
/* * groupRenderTopTabHighlight * */ void groupRenderTopTabHighlight (GroupSelection *group) { GroupTabBar *bar = group->tabBar; GroupCairoLayer *layer; cairo_t *cr; int width, height; if (!bar || !HAS_TOP_WIN (group) || !bar->selectionLayer || !bar->selectionLayer->cairo) { return; } width = group->topTab->region->extents.x2 - group->topTab->region->extents.x1; height = group->topTab->region->extents.y2 - group->topTab->region->extents.y1; bar->selectionLayer = groupRebuildCairoLayer (group->screen, bar->selectionLayer, width, height); if (!bar->selectionLayer) return; layer = bar->selectionLayer; cr = bar->selectionLayer->cairo; /* fill */ cairo_set_line_width (cr, 2); cairo_set_source_rgba (cr, (group->color[0] / 65535.0f), (group->color[1] / 65535.0f), (group->color[2] / 65535.0f), (group->color[3] / (65535.0f * 2))); cairo_move_to (cr, 0, 0); cairo_rectangle (cr, 0, 0, width, height); cairo_fill_preserve (cr); /* outline */ cairo_set_source_rgba (cr, (group->color[0] / 65535.0f), (group->color[1] / 65535.0f), (group->color[2] / 65535.0f), (group->color[3] / 65535.0f)); cairo_stroke (cr); imageBufferToTexture (group->screen, &layer->texture, (char*) layer->buffer, layer->texWidth, layer->texHeight); }
/* * groupPreparePaintScreen * */ void groupPreparePaintScreen (CompScreen *s, int msSinceLastPaint) { GroupSelection *group, *next; GROUP_SCREEN (s); UNWRAP (gs, s, preparePaintScreen); (*s->preparePaintScreen)(s, msSinceLastPaint); WRAP (gs, s, preparePaintScreen, groupPreparePaintScreen); group = gs->groups; while (group) { GroupTabBar *bar = group->tabBar; if (bar) { groupApplyForces (s, bar, (gs->dragged) ? gs->draggedSlot : NULL); groupApplySpeeds (s, group, msSinceLastPaint); if ((bar->state != PaintOff) && HAS_TOP_WIN (group)) groupHandleHoverDetection (group); if (bar->state == PaintFadeIn || bar->state == PaintFadeOut) groupHandleTabBarFade (group, msSinceLastPaint); if (bar->textLayer) groupHandleTextFade (group, msSinceLastPaint); if (bar->bgAnimation) groupHandleTabBarAnimation (group, msSinceLastPaint); } if (group->changeState != NoTabChange) { group->changeAnimationTime -= msSinceLastPaint; if (group->changeAnimationTime <= 0) groupHandleAnimation (group); } /* groupDrawTabAnimation may delete the group, so better save the pointer to the next chain element */ next = group->next; if (group->tabbingState != NoTabbing) groupDrawTabAnimation (group, msSinceLastPaint); group = next; } }
/* * 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); } }
/* * groupRenderTabBarBackground * */ void groupRenderTabBarBackground(GroupSelection *group) { GroupCairoLayer *layer; cairo_t *cr; int width, height, radius; int borderWidth; float r, g, b, a; double x0, y0, x1, y1; CompScreen *s = group->screen; GroupTabBar *bar = group->tabBar; if (!bar || !HAS_TOP_WIN (group) || !bar->bgLayer || !bar->bgLayer->cairo) return; width = bar->region->extents.x2 - bar->region->extents.x1; height = bar->region->extents.y2 - bar->region->extents.y1; radius = groupGetBorderRadius (s); if (width > bar->bgLayer->texWidth) width = bar->bgLayer->texWidth; if (radius > width / 2) radius = width / 2; layer = bar->bgLayer; cr = layer->cairo; groupClearCairoLayer (layer); borderWidth = groupGetBorderWidth (s); cairo_set_line_width (cr, borderWidth); cairo_save (cr); x0 = borderWidth / 2.0f; y0 = borderWidth / 2.0f; x1 = width - borderWidth / 2.0f; y1 = height - borderWidth / 2.0f; cairo_move_to (cr, x0 + radius, y0); cairo_arc (cr, x1 - radius, y0 + radius, radius, M_PI * 1.5, M_PI * 2.0); cairo_arc (cr, x1 - radius, y1 - radius, radius, 0.0, M_PI * 0.5); cairo_arc (cr, x0 + radius, y1 - radius, radius, M_PI * 0.5, M_PI); cairo_arc (cr, x0 + radius, y0 + radius, radius, M_PI, M_PI * 1.5); cairo_close_path (cr); switch (groupGetTabStyle (s)) { case TabStyleSimple: { /* base color */ r = groupGetTabBaseColorRed (s) / 65535.0f; g = groupGetTabBaseColorGreen (s) / 65535.0f; b = groupGetTabBaseColorBlue (s) / 65535.0f; a = groupGetTabBaseColorAlpha (s) / 65535.0f; cairo_set_source_rgba (cr, r, g, b, a); cairo_fill_preserve (cr); break; } case TabStyleGradient: { /* fill */ cairo_pattern_t *pattern; pattern = cairo_pattern_create_linear (0, 0, width, height); /* highlight color */ r = groupGetTabHighlightColorRed (s) / 65535.0f; g = groupGetTabHighlightColorGreen (s) / 65535.0f; b = groupGetTabHighlightColorBlue (s) / 65535.0f; a = groupGetTabHighlightColorAlpha (s) / 65535.0f; cairo_pattern_add_color_stop_rgba (pattern, 0.0f, r, g, b, a); /* base color */ r = groupGetTabBaseColorRed (s) / 65535.0f; g = groupGetTabBaseColorGreen (s) / 65535.0f; b = groupGetTabBaseColorBlue (s) / 65535.0f; a = groupGetTabBaseColorAlpha (s) / 65535.0f; cairo_pattern_add_color_stop_rgba (pattern, 1.0f, r, g, b, a); cairo_set_source (cr, pattern); cairo_fill_preserve (cr); cairo_pattern_destroy (pattern); break; } case TabStyleGlass: { cairo_pattern_t *pattern; cairo_save (cr); /* clip width rounded rectangle */ cairo_clip (cr); /* ===== HIGHLIGHT ===== */ /* make draw the shape for the highlight and create a pattern for it */ cairo_rectangle (cr, 0, 0, width, height / 2); pattern = cairo_pattern_create_linear (0, 0, 0, height); /* highlight color */ r = groupGetTabHighlightColorRed (s) / 65535.0f; g = groupGetTabHighlightColorGreen (s) / 65535.0f; b = groupGetTabHighlightColorBlue (s) / 65535.0f; a = groupGetTabHighlightColorAlpha (s) / 65535.0f; cairo_pattern_add_color_stop_rgba (pattern, 0.0f, r, g, b, a); /* base color */ r = groupGetTabBaseColorRed (s) / 65535.0f; g = groupGetTabBaseColorGreen (s) / 65535.0f; b = groupGetTabBaseColorBlue (s) / 65535.0f; a = groupGetTabBaseColorAlpha (s) / 65535.0f; cairo_pattern_add_color_stop_rgba (pattern, 0.6f, r, g, b, a); cairo_set_source (cr, pattern); cairo_fill (cr); cairo_pattern_destroy (pattern); /* ==== SHADOW ===== */ /* make draw the shape for the show and create a pattern for it */ cairo_rectangle (cr, 0, height / 2, width, height); pattern = cairo_pattern_create_linear (0, 0, 0, height); /* we don't want to use a full highlight here so we mix the colors */ r = (groupGetTabHighlightColorRed (s) + groupGetTabBaseColorRed (s)) / (2 * 65535.0f); g = (groupGetTabHighlightColorGreen (s) + groupGetTabBaseColorGreen (s)) / (2 * 65535.0f); b = (groupGetTabHighlightColorBlue (s) + groupGetTabBaseColorBlue (s)) / (2 * 65535.0f); a = (groupGetTabHighlightColorAlpha (s) + groupGetTabBaseColorAlpha (s)) / (2 * 65535.0f); cairo_pattern_add_color_stop_rgba (pattern, 1.0f, r, g, b, a); /* base color */ r = groupGetTabBaseColorRed (s) / 65535.0f; g = groupGetTabBaseColorGreen (s) / 65535.0f; b = groupGetTabBaseColorBlue (s) / 65535.0f; a = groupGetTabBaseColorAlpha (s) / 65535.0f; cairo_pattern_add_color_stop_rgba (pattern, 0.5f, r, g, b, a); cairo_set_source (cr, pattern); cairo_fill (cr); cairo_pattern_destroy (pattern); cairo_restore (cr); /* draw shape again for the outline */ cairo_move_to (cr, x0 + radius, y0); cairo_arc (cr, x1 - radius, y0 + radius, radius, M_PI * 1.5, M_PI * 2.0); cairo_arc (cr, x1 - radius, y1 - radius, radius, 0.0, M_PI * 0.5); cairo_arc (cr, x0 + radius, y1 - radius, radius, M_PI * 0.5, M_PI); cairo_arc (cr, x0 + radius, y0 + radius, radius, M_PI, M_PI * 1.5); break; } case TabStyleMetal: { /* fill */ cairo_pattern_t *pattern; pattern = cairo_pattern_create_linear (0, 0, 0, height); /* base color #1 */ r = groupGetTabBaseColorRed (s) / 65535.0f; g = groupGetTabBaseColorGreen (s) / 65535.0f; b = groupGetTabBaseColorBlue (s) / 65535.0f; a = groupGetTabBaseColorAlpha (s) / 65535.0f; cairo_pattern_add_color_stop_rgba (pattern, 0.0f, r, g, b, a); /* highlight color */ r = groupGetTabHighlightColorRed (s) / 65535.0f; g = groupGetTabHighlightColorGreen (s) / 65535.0f; b = groupGetTabHighlightColorBlue (s) / 65535.0f; a = groupGetTabHighlightColorAlpha (s) / 65535.0f; cairo_pattern_add_color_stop_rgba (pattern, 0.55f, r, g, b, a); /* base color #2 */ r = groupGetTabBaseColorRed (s) / 65535.0f; g = groupGetTabBaseColorGreen (s) / 65535.0f; b = groupGetTabBaseColorBlue (s) / 65535.0f; a = groupGetTabBaseColorAlpha (s) / 65535.0f; cairo_pattern_add_color_stop_rgba (pattern, 1.0f, r, g, b, a); cairo_set_source (cr, pattern); cairo_fill_preserve (cr); cairo_pattern_destroy (pattern); break; } case TabStyleMurrina: { double ratio, transX; cairo_pattern_t *pattern; cairo_save (cr); /* clip width rounded rectangle */ cairo_clip_preserve (cr); /* ==== TOP ==== */ x0 = borderWidth / 2.0; y0 = borderWidth / 2.0; x1 = width - borderWidth / 2.0; y1 = height - borderWidth / 2.0; radius = (y1 - y0) / 2; /* setup pattern */ pattern = cairo_pattern_create_linear (0, 0, 0, height); /* we don't want to use a full highlight here so we mix the colors */ r = (groupGetTabHighlightColorRed (s) + groupGetTabBaseColorRed (s)) / (2 * 65535.0f); g = (groupGetTabHighlightColorGreen (s) + groupGetTabBaseColorGreen (s)) / (2 * 65535.0f); b = (groupGetTabHighlightColorBlue (s) + groupGetTabBaseColorBlue (s)) / (2 * 65535.0f); a = (groupGetTabHighlightColorAlpha (s) + groupGetTabBaseColorAlpha (s)) / (2 * 65535.0f); cairo_pattern_add_color_stop_rgba (pattern, 0.0f, r, g, b, a); /* highlight color */ r = groupGetTabHighlightColorRed (s) / 65535.0f; g = groupGetTabHighlightColorGreen (s) / 65535.0f; b = groupGetTabHighlightColorBlue (s) / 65535.0f; a = groupGetTabHighlightColorAlpha (s) / 65535.0f; cairo_pattern_add_color_stop_rgba (pattern, 1.0f, r, g, b, a); cairo_set_source (cr, pattern); cairo_fill (cr); cairo_pattern_destroy (pattern); /* ==== BOTTOM ===== */ x0 = borderWidth / 2.0; y0 = borderWidth / 2.0; x1 = width - borderWidth / 2.0; y1 = height - borderWidth / 2.0; radius = (y1 - y0) / 2; ratio = (double)width / (double)height; transX = width - (width * ratio); cairo_move_to (cr, x1, y1); cairo_line_to (cr, x1, y0); if (width < height) { cairo_translate (cr, transX, 0); cairo_scale (cr, ratio, 1.0); } cairo_arc (cr, x1 - radius, y0, radius, 0.0, M_PI * 0.5); if (width < height) { cairo_scale (cr, 1.0 / ratio, 1.0); cairo_translate (cr, -transX, 0); cairo_scale (cr, ratio, 1.0); } cairo_arc_negative (cr, x0 + radius, y1, radius, M_PI * 1.5, M_PI); cairo_close_path (cr); /* setup pattern */ pattern = cairo_pattern_create_linear (0, 0, 0, height); /* base color */ r = groupGetTabBaseColorRed (s) / 65535.0f; g = groupGetTabBaseColorGreen (s) / 65535.0f; b = groupGetTabBaseColorBlue (s) / 65535.0f; a = groupGetTabBaseColorAlpha (s) / 65535.0f; cairo_pattern_add_color_stop_rgba (pattern, 0.0f, r, g, b, a); /* we don't want to use a full highlight here so we mix the colors */ r = (groupGetTabHighlightColorRed (s) + groupGetTabBaseColorRed (s)) / (2 * 65535.0f); g = (groupGetTabHighlightColorGreen (s) + groupGetTabBaseColorGreen (s)) / (2 * 65535.0f); b = (groupGetTabHighlightColorBlue (s) + groupGetTabBaseColorBlue (s)) / (2 * 65535.0f); a = (groupGetTabHighlightColorAlpha (s) + groupGetTabBaseColorAlpha (s)) / (2 * 65535.0f); cairo_pattern_add_color_stop_rgba (pattern, 1.0f, r, g, b, a); cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); cairo_set_source (cr, pattern); cairo_fill (cr); cairo_pattern_destroy (pattern); cairo_set_operator (cr, CAIRO_OPERATOR_OVER); cairo_restore (cr); /* draw shape again for the outline */ x0 = borderWidth / 2.0; y0 = borderWidth / 2.0; x1 = width - borderWidth / 2.0; y1 = height - borderWidth / 2.0; radius = groupGetBorderRadius (s); cairo_move_to (cr, x0 + radius, y0); cairo_arc (cr, x1 - radius, y0 + radius, radius, M_PI * 1.5, M_PI * 2.0); cairo_arc (cr, x1 - radius, y1 - radius, radius, 0.0, M_PI * 0.5); cairo_arc (cr, x0 + radius, y1 - radius, radius, M_PI * 0.5, M_PI); cairo_arc (cr, x0 + radius, y0 + radius, radius, M_PI, M_PI * 1.5); break; } default: break; } /* outline */ r = groupGetTabBorderColorRed (s) / 65535.0f; g = groupGetTabBorderColorGreen (s) / 65535.0f; b = groupGetTabBorderColorBlue (s) / 65535.0f; a = groupGetTabBorderColorAlpha (s) / 65535.0f; cairo_set_source_rgba (cr, r, g, b, a); if (bar->bgAnimation != AnimationNone) cairo_stroke_preserve (cr); else cairo_stroke (cr); switch (bar->bgAnimation) { case AnimationPulse: { double animationProgress; double alpha; animationProgress = bar->bgAnimationTime / (groupGetPulseTime (s) * 1000.0); alpha = sin ((2 * PI * animationProgress) - 1.55)*0.5 + 0.5; if (alpha <= 0) break; cairo_save (cr); cairo_clip (cr); cairo_set_operator (cr, CAIRO_OPERATOR_XOR); cairo_rectangle (cr, 0.0, 0.0, width, height); cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, alpha); cairo_fill (cr); cairo_restore (cr); break; } case AnimationReflex: { double animationProgress; double reflexWidth; double posX, alpha; cairo_pattern_t *pattern; animationProgress = bar->bgAnimationTime / (groupGetReflexTime (s) * 1000.0); reflexWidth = (bar->nSlots / 2.0) * 30; posX = (width + reflexWidth * 2.0) * animationProgress; alpha = sin (PI * animationProgress) * 0.55; if (alpha <= 0) break; cairo_save (cr); cairo_clip (cr); pattern = cairo_pattern_create_linear (posX - reflexWidth, 0.0, posX, height); cairo_pattern_add_color_stop_rgba (pattern, 0.0f, 1.0, 1.0, 1.0, 0.0); cairo_pattern_add_color_stop_rgba (pattern, 0.5f, 1.0, 1.0, 1.0, alpha); cairo_pattern_add_color_stop_rgba (pattern, 1.0f, 1.0, 1.0, 1.0, 0.0); cairo_rectangle (cr, 0.0, 0.0, width, height); cairo_set_source (cr, pattern); cairo_fill (cr); cairo_restore (cr); cairo_pattern_destroy (pattern); break; } case AnimationNone: default: break; } /* draw inner outline */ cairo_move_to (cr, x0 + radius + 1.0, y0 + 1.0); cairo_arc (cr, x1 - radius - 1.0, y0 + radius + 1.0, radius, M_PI * 1.5, M_PI * 2.0); cairo_arc (cr, x1 - radius - 1.0, y1 - radius - 1.0, radius, 0.0, M_PI * 0.5); cairo_arc (cr, x0 + radius + 1.0, y1 - radius - 1.0, radius, M_PI * 0.5, M_PI); cairo_arc (cr, x0 + radius + 1.0, y0 + radius + 1.0, radius, M_PI, M_PI * 1.5); cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.3); cairo_stroke(cr); cairo_restore (cr); imageBufferToTexture (s, &layer->texture, (char*) layer->buffer, layer->texWidth, layer->texHeight); }
/* * groupPaintWindow * */ Bool groupPaintWindow (CompWindow *w, const WindowPaintAttrib *attrib, const CompTransform *transform, Region region, unsigned int mask) { Bool status; Bool doRotate, doTabbing, showTabbar; CompScreen *s = w->screen; GROUP_SCREEN (s); GROUP_WINDOW (w); if (gw->group) { GroupSelection *group = gw->group; doRotate = (group->changeState != NoTabChange) && HAS_TOP_WIN (group) && HAS_PREV_TOP_WIN (group) && (IS_TOP_TAB (w, group) || IS_PREV_TOP_TAB (w, group)); doTabbing = (gw->animateState & (IS_ANIMATED | FINISHED_ANIMATION)) && !(IS_TOP_TAB (w, group) && (group->tabbingState == Tabbing)); showTabbar = group->tabBar && (group->tabBar->state != PaintOff) && (((IS_TOP_TAB (w, group)) && ((group->changeState == NoTabChange) || (group->changeState == TabChangeNewIn))) || (IS_PREV_TOP_TAB (w, group) && (group->changeState == TabChangeOldOut))); } else { doRotate = FALSE; doTabbing = FALSE; showTabbar = FALSE; } if (gw->windowHideInfo) mask |= PAINT_WINDOW_NO_CORE_INSTANCE_MASK; if (gw->inSelection || gw->resizeGeometry || doRotate || doTabbing || showTabbar) { WindowPaintAttrib wAttrib = *attrib; CompTransform wTransform = *transform; float animProgress = 0.0f; int drawnPosX = 0, drawnPosY = 0; if (gw->inSelection) { const BananaValue * option_select_opacity = bananaGetOption (bananaIndex, "select_opacity", s->screenNum); const BananaValue * option_select_saturation = bananaGetOption (bananaIndex, "select_saturation", s->screenNum); const BananaValue * option_select_brightness = bananaGetOption (bananaIndex, "select_brightness", s->screenNum); wAttrib.opacity = OPAQUE * option_select_opacity->i / 100; wAttrib.saturation = COLOR * option_select_saturation->i / 100; wAttrib.brightness = BRIGHT * option_select_brightness->i / 100; } if (doTabbing) { /* fade the window out */ float progress; int distanceX, distanceY; float origDistance, distance; if (gw->animateState & FINISHED_ANIMATION) { drawnPosX = gw->destination.x; drawnPosY = gw->destination.y; } else { drawnPosX = gw->orgPos.x + gw->tx; drawnPosY = gw->orgPos.y + gw->ty; } distanceX = drawnPosX - gw->destination.x; distanceY = drawnPosY - gw->destination.y; distance = sqrt (pow (distanceX, 2) + pow (distanceY, 2)); distanceX = (gw->orgPos.x - gw->destination.x); distanceY = (gw->orgPos.y - gw->destination.y); origDistance = sqrt (pow (distanceX, 2) + pow (distanceY, 2)); if (!distanceX && !distanceY) progress = 1.0f; else progress = 1.0f - (distance / origDistance); animProgress = progress; progress = MAX (progress, 0.0f); if (gw->group->tabbingState == Tabbing) progress = 1.0f - progress; wAttrib.opacity = (float)wAttrib.opacity * progress; } if (doRotate) { const BananaValue * option_change_animation_time = bananaGetOption (bananaIndex, "change_animation_time", s->screenNum); float timeLeft = gw->group->changeAnimationTime; int animTime = option_change_animation_time->f * 500; if (gw->group->changeState == TabChangeOldOut) timeLeft += animTime; /* 0 at the beginning, 1 at the end */ animProgress = 1 - (timeLeft / (2 * animTime)); } if (gw->resizeGeometry) { int xOrigin, yOrigin; float xScale, yScale; BoxRec box; groupGetStretchRectangle (w, &box, &xScale, &yScale); xOrigin = w->attrib.x - w->input.left; yOrigin = w->attrib.y - w->input.top; matrixTranslate (&wTransform, xOrigin, yOrigin, 0.0f); matrixScale (&wTransform, xScale, yScale, 1.0f); matrixTranslate (&wTransform, (gw->resizeGeometry->x - w->attrib.x) / xScale - xOrigin, (gw->resizeGeometry->y - w->attrib.y) / yScale - yOrigin, 0.0f); mask |= PAINT_WINDOW_TRANSFORMED_MASK; } else if (doRotate || doTabbing) { float animWidth, animHeight; float animScaleX, animScaleY; CompWindow *morphBase, *morphTarget; if (doTabbing) { if (gw->group->tabbingState == Tabbing) { morphBase = w; morphTarget = TOP_TAB (gw->group); } else { morphTarget = w; if (HAS_TOP_WIN (gw->group)) morphBase = TOP_TAB (gw->group); else morphBase = gw->group->lastTopTab; } } else { morphBase = PREV_TOP_TAB (gw->group); morphTarget = TOP_TAB (gw->group); } animWidth = (1 - animProgress) * WIN_REAL_WIDTH (morphBase) + animProgress * WIN_REAL_WIDTH (morphTarget); animHeight = (1 - animProgress) * WIN_REAL_HEIGHT (morphBase) + animProgress * WIN_REAL_HEIGHT (morphTarget); animWidth = MAX (1.0f, animWidth); animHeight = MAX (1.0f, animHeight); animScaleX = animWidth / WIN_REAL_WIDTH (w); animScaleY = animHeight / WIN_REAL_HEIGHT (w); if (doRotate) matrixScale (&wTransform, 1.0f, 1.0f, 1.0f / s->width); matrixTranslate (&wTransform, WIN_REAL_X (w) + WIN_REAL_WIDTH (w) / 2.0f, WIN_REAL_Y (w) + WIN_REAL_HEIGHT (w) / 2.0f, 0.0f); if (doRotate) { float rotateAngle = animProgress * 180.0f; if (IS_TOP_TAB (w, gw->group)) rotateAngle += 180.0f; if (gw->group->changeAnimationDirection < 0) rotateAngle *= -1.0f; matrixRotate (&wTransform, rotateAngle, 0.0f, 1.0f, 0.0f); } if (doTabbing) matrixTranslate (&wTransform, drawnPosX - WIN_X (w), drawnPosY - WIN_Y (w), 0.0f); matrixScale (&wTransform, animScaleX, animScaleY, 1.0f); matrixTranslate (&wTransform, -(WIN_REAL_X (w) + WIN_REAL_WIDTH (w) / 2.0f), -(WIN_REAL_Y (w) + WIN_REAL_HEIGHT (w) / 2.0f), 0.0f); mask |= PAINT_WINDOW_TRANSFORMED_MASK; } UNWRAP (gs, s, paintWindow); status = (*s->paintWindow)(w, &wAttrib, &wTransform, region, mask); if (showTabbar) groupPaintTabBar (gw->group, &wAttrib, &wTransform, mask, region); WRAP (gs, s, paintWindow, groupPaintWindow); } else { UNWRAP (gs, s, paintWindow); status = (*s->paintWindow)(w, attrib, transform, region, mask); WRAP (gs, s, paintWindow, groupPaintWindow); } return status; }
/* * groupPaintTabBar * */ static void groupPaintTabBar (GroupSelection *group, const WindowPaintAttrib *wAttrib, const CompTransform *transform, unsigned int mask, Region clipRegion) { CompWindow *topTab; CompScreen *s = group->screen; GroupTabBar *bar = group->tabBar; int count; REGION box; GROUP_SCREEN (s); if (HAS_TOP_WIN (group)) topTab = TOP_TAB (group); else topTab = PREV_TOP_TAB (group); #define PAINT_BG 0 #define PAINT_SEL 1 #define PAINT_THUMBS 2 #define PAINT_TEXT 3 #define PAINT_MAX 4 box.rects = &box.extents; box.numRects = 1; const BananaValue * option_fade_time = bananaGetOption (bananaIndex, "fade_time", s->screenNum); const BananaValue * option_mipmaps = bananaGetOption (bananaIndex, "mipmaps", s->screenNum); const BananaValue * option_fade_text_time = bananaGetOption (bananaIndex, "fade_text_time", s->screenNum); for (count = 0; count < PAINT_MAX; count++) { int alpha = OPAQUE; float wScale = 1.0f, hScale = 1.0f; GroupCairoLayer *layer = NULL; if (bar->state == PaintFadeIn) alpha -= alpha * bar->animationTime / (option_fade_time->f * 1000); else if (bar->state == PaintFadeOut) alpha = alpha * bar->animationTime / (option_fade_time->f * 1000); switch (count) { case PAINT_BG: { int newWidth; layer = bar->bgLayer; /* handle the repaint of the background */ newWidth = bar->region->extents.x2 - bar->region->extents.x1; if (layer && (newWidth > layer->texWidth)) newWidth = layer->texWidth; wScale = (double) (bar->region->extents.x2 - bar->region->extents.x1) / (double) newWidth; /* FIXME: maybe move this over to groupResizeTabBarRegion - the only problem is that we would have 2 redraws if there is an animation */ if (newWidth != bar->oldWidth || bar->bgAnimation) groupRenderTabBarBackground (group); bar->oldWidth = newWidth; box.extents = bar->region->extents; } break; case PAINT_SEL: if (group->topTab != gs->draggedSlot) { layer = bar->selectionLayer; box.extents = group->topTab->region->extents; } break; case PAINT_THUMBS: { GLenum oldTextureFilter; GroupTabBarSlot *slot; oldTextureFilter = display.textureFilter; if (option_mipmaps->b) display.textureFilter = GL_LINEAR_MIPMAP_LINEAR; for (slot = bar->slots; slot; slot = slot->next) { if (slot != gs->draggedSlot || !gs->dragged) groupPaintThumb (group, slot, transform, wAttrib->opacity); } display.textureFilter = oldTextureFilter; } break; case PAINT_TEXT: if (bar->textLayer && (bar->textLayer->state != PaintOff)) { layer = bar->textLayer; box.extents.x1 = bar->region->extents.x1 + 5; box.extents.x2 = bar->region->extents.x1 + bar->textLayer->texWidth + 5; box.extents.y1 = bar->region->extents.y2 - bar->textLayer->texHeight - 5; box.extents.y2 = bar->region->extents.y2 - 5; if (box.extents.x2 > bar->region->extents.x2) box.extents.x2 = bar->region->extents.x2; /* recalculate the alpha again for text fade... */ if (layer->state == PaintFadeIn) alpha -= alpha * layer->animationTime / (option_fade_text_time->f * 1000); else if (layer->state == PaintFadeOut) alpha = alpha * layer->animationTime / (option_fade_text_time->f * 1000); } break; } if (layer) { CompMatrix matrix = layer->texture.matrix; /* remove the old x1 and y1 so we have a relative value */ box.extents.x2 -= box.extents.x1; box.extents.y2 -= box.extents.y1; box.extents.x1 = (box.extents.x1 - topTab->attrib.x) / wScale + topTab->attrib.x; box.extents.y1 = (box.extents.y1 - topTab->attrib.y) / hScale + topTab->attrib.y; /* now add the new x1 and y1 so we have a absolute value again, also we don't want to stretch the texture... */ if (box.extents.x2 * wScale < layer->texWidth) box.extents.x2 += box.extents.x1; else box.extents.x2 = box.extents.x1 + layer->texWidth; if (box.extents.y2 * hScale < layer->texHeight) box.extents.y2 += box.extents.y1; else box.extents.y2 = box.extents.y1 + layer->texHeight; matrix.x0 -= box.extents.x1 * matrix.xx; matrix.y0 -= box.extents.y1 * matrix.yy; topTab->vCount = topTab->indexCount = 0; addWindowGeometry (topTab, &matrix, 1, &box, clipRegion); if (topTab->vCount) { FragmentAttrib fragment; CompTransform wTransform = *transform; matrixTranslate (&wTransform, WIN_X (topTab), WIN_Y (topTab), 0.0f); matrixScale (&wTransform, wScale, hScale, 1.0f); matrixTranslate (&wTransform, wAttrib->xTranslate / wScale - WIN_X (topTab), wAttrib->yTranslate / hScale - WIN_Y (topTab), 0.0f); glPushMatrix (); glLoadMatrixf (wTransform.m); alpha = alpha * ((float)wAttrib->opacity / OPAQUE); initFragmentAttrib (&fragment, wAttrib); fragment.opacity = alpha; (*s->drawWindowTexture)(topTab, &layer->texture, &fragment, mask | PAINT_WINDOW_BLEND_MASK | PAINT_WINDOW_TRANSFORMED_MASK | PAINT_WINDOW_TRANSLUCENT_MASK); glPopMatrix (); } } } }
/* * TextLayer::render * * Renders some text without a background, without automatically * binding the text pixmap to a texture (since we need to bind it later) * */ void TextLayer::render () { int twidth, theight; Pixmap pixmap = None; GROUP_SCREEN (screen); if (!HAS_TOP_WIN (mGroup)) return; /* Maximum text width is the tab bar width */ twidth = mGroup->mTabBar->mRegion.boundingRect ().width (); theight = mGroup->mTabBar->mRegion.boundingRect ().height (); if (mGroup->mTabBar->mTextSlot && mGroup->mTabBar->mTextSlot->mWindow && gTextAvailable) { CompText::Attrib textAttrib; textAttrib.family = "Sans"; textAttrib.size = gs->optionGetTabbarFontSize (); /* Bold text, ellipsize if there is not enough room and do not * automatically bind pixmap to texture */ textAttrib.flags = CompText::StyleBold | CompText::Ellipsized | CompText::NoAutoBinding; textAttrib.color[0] = gs->optionGetTabbarFontColorRed (); textAttrib.color[1] = gs->optionGetTabbarFontColorGreen (); textAttrib.color[2] = gs->optionGetTabbarFontColorBlue (); textAttrib.color[3] = gs->optionGetTabbarFontColorAlpha (); textAttrib.maxWidth = twidth; textAttrib.maxHeight = theight; /* Render title of the top window */ if (gs->mText.renderWindowTitle ( mGroup->mTabBar->mTextSlot->mWindow->id (), false, textAttrib)) { pixmap = gs->mText.getPixmap (); twidth = gs->mText.getWidth (); theight = gs->mText.getHeight (); } } if (!pixmap) { /* getting the pixmap failed, so create an empty one */ pixmap = XCreatePixmap (screen->dpy (), screen->root (), twidth, theight, 32); if (pixmap) { XGCValues gcv; GC gc; gcv.foreground = 0x00000000; gcv.plane_mask = 0xffffffff; gc = XCreateGC (screen->dpy (), pixmap, GCForeground, &gcv); XFillRectangle (screen->dpy (), pixmap, gc, 0, 0, twidth, theight); XFreeGC (screen->dpy (), gc); } } setWidth (twidth); setHeight (theight); if (pixmap) { mTexture.clear (); mPixmap = pixmap; /* Text layer's texture is bound here, this can be re used * in TextureLayer::paint */ mTexture = GLTexture::bindPixmapToTexture (mPixmap, width (), height (), 32); } }
/* * BackgroundLayer::render * * Render the background to the tab bar, also render the tab bar animation * */ void BackgroundLayer::render () { cairo_t *cr; int twidth, theight, radius; int borderWidth; float r, g, b, a; double x0, y0, x1, y1; GROUP_SCREEN (screen); if (!HAS_TOP_WIN (mGroup) || !mCairo) return; /* Dimentions are the tab bar's region */ twidth = mGroup->mTabBar->mRegion.boundingRect ().width (); theight = mGroup->mTabBar->mRegion.boundingRect ().height (); radius = gs->optionGetBorderRadius (); /* Do not draw more than the tab bar width */ if (twidth > width ()) twidth = width (); /* Border radius should not exceed * half of the tab bar height */ if (radius > twidth / 2) radius = twidth / 2; cr = mCairo; /* Clear the layer */ clear (); /* Draw the border around the tab bar */ borderWidth = gs->optionGetBorderWidth (); cairo_set_line_width (cr, borderWidth); cairo_save (cr); /* Move to the center of where we want to draw the line */ x0 = borderWidth / 2.0f; y0 = borderWidth / 2.0f; /* The center of where we want to draw the opposite line */ x1 = twidth - borderWidth / 2.0f; y1 = theight - borderWidth / 2.0f; cairo_move_to (cr, x0 + radius, y0); /* Arc the top right corner */ cairo_arc (cr, x1 - radius, y0 + radius, radius, M_PI * 1.5, M_PI * 2.0); /* Arc the bottom right corner */ cairo_arc (cr, x1 - radius, y1 - radius, radius, 0.0, M_PI * 0.5); /* Arc the bottom left corner */ cairo_arc (cr, x0 + radius, y1 - radius, radius, M_PI * 0.5, M_PI); /* Arc the top left corner */ cairo_arc (cr, x0 + radius, y0 + radius, radius, M_PI, M_PI * 1.5); cairo_close_path (cr); /* There are 5 different tab styles here: * Simple: draws a simple filled rect * Gradient: left to right gradient between base and highlight * Glass: left to right gradient, stopping at 60% and drawing a shadow * Metal: base -> highlight -> base gradient * Murrina: draws an arc between the two corners blending base and highlight */ switch (gs->optionGetTabStyle ()) { case GroupOptions::TabStyleSimple: { /* base color */ r = gs->optionGetTabBaseColorRed () / 65535.0f; g = gs->optionGetTabBaseColorGreen () / 65535.0f; b = gs->optionGetTabBaseColorBlue () / 65535.0f; a = gs->optionGetTabBaseColorAlpha () / 65535.0f; cairo_set_source_rgba (cr, r, g, b, a); cairo_fill_preserve (cr); break; } case GroupOptions::TabStyleGradient: { /* fill */ cairo_pattern_t *pattern; pattern = cairo_pattern_create_linear (0, 0, twidth, theight); /* highlight color */ r = gs->optionGetTabHighlightColorRed () / 65535.0f; g = gs->optionGetTabHighlightColorGreen () / 65535.0f; b = gs->optionGetTabHighlightColorBlue () / 65535.0f; a = gs->optionGetTabHighlightColorAlpha () / 65535.0f; cairo_pattern_add_color_stop_rgba (pattern, 0.0f, r, g, b, a); /* base color */ r = gs->optionGetTabBaseColorRed () / 65535.0f; g = gs->optionGetTabBaseColorGreen () / 65535.0f; b = gs->optionGetTabBaseColorBlue () / 65535.0f; a = gs->optionGetTabBaseColorAlpha () / 65535.0f; cairo_pattern_add_color_stop_rgba (pattern, 1.0f, r, g, b, a); cairo_set_source (cr, pattern); cairo_fill_preserve (cr); cairo_pattern_destroy (pattern); break; } case GroupOptions::TabStyleGlass: { cairo_pattern_t *pattern; cairo_save (cr); /* clip width rounded rectangle */ cairo_clip (cr); /* ===== HIGHLIGHT ===== */ /* make draw the shape for the highlight and create a pattern for it */ cairo_rectangle (cr, 0, 0, twidth, theight / 2); pattern = cairo_pattern_create_linear (0, 0, 0, theight); /* highlight color */ r = gs->optionGetTabHighlightColorRed () / 65535.0f; g = gs->optionGetTabHighlightColorGreen () / 65535.0f; b = gs->optionGetTabHighlightColorBlue () / 65535.0f; a = gs->optionGetTabHighlightColorAlpha () / 65535.0f; cairo_pattern_add_color_stop_rgba (pattern, 0.0f, r, g, b, a); /* base color */ r = gs->optionGetTabBaseColorRed () / 65535.0f; g = gs->optionGetTabBaseColorGreen () / 65535.0f; b = gs->optionGetTabBaseColorBlue () / 65535.0f; a = gs->optionGetTabBaseColorAlpha () / 65535.0f; cairo_pattern_add_color_stop_rgba (pattern, 0.6f, r, g, b, a); cairo_set_source (cr, pattern); cairo_fill (cr); cairo_pattern_destroy (pattern); /* ==== SHADOW ===== */ /* make draw the shape for the show and create a pattern for it */ cairo_rectangle (cr, 0, theight / 2, twidth, theight); pattern = cairo_pattern_create_linear (0, 0, 0, theight); /* we don't want to use a full highlight here so we mix the colors */ r = (gs->optionGetTabHighlightColorRed () + gs->optionGetTabBaseColorRed ()) / (2 * 65535.0f); g = (gs->optionGetTabHighlightColorGreen () + gs->optionGetTabBaseColorGreen ()) / (2 * 65535.0f); b = (gs->optionGetTabHighlightColorBlue () + gs->optionGetTabBaseColorBlue ()) / (2 * 65535.0f); a = (gs->optionGetTabHighlightColorAlpha () + gs->optionGetTabBaseColorAlpha ()) / (2 * 65535.0f); cairo_pattern_add_color_stop_rgba (pattern, 1.0f, r, g, b, a); /* base color */ r = gs->optionGetTabBaseColorRed () / 65535.0f; g = gs->optionGetTabBaseColorGreen () / 65535.0f; b = gs->optionGetTabBaseColorBlue () / 65535.0f; a = gs->optionGetTabBaseColorAlpha () / 65535.0f; cairo_pattern_add_color_stop_rgba (pattern, 0.5f, r, g, b, a); cairo_set_source (cr, pattern); cairo_fill (cr); cairo_pattern_destroy (pattern); cairo_restore (cr); /* draw shape again for the outline */ cairo_move_to (cr, x0 + radius, y0); cairo_arc (cr, x1 - radius, y0 + radius, radius, M_PI * 1.5, M_PI * 2.0); cairo_arc (cr, x1 - radius, y1 - radius, radius, 0.0, M_PI * 0.5); cairo_arc (cr, x0 + radius, y1 - radius, radius, M_PI * 0.5, M_PI); cairo_arc (cr, x0 + radius, y0 + radius, radius, M_PI, M_PI * 1.5); break; } case GroupOptions::TabStyleMetal: { /* fill */ cairo_pattern_t *pattern; pattern = cairo_pattern_create_linear (0, 0, 0, theight); /* base color #1 */ r = gs->optionGetTabBaseColorRed () / 65535.0f; g = gs->optionGetTabBaseColorGreen () / 65535.0f; b = gs->optionGetTabBaseColorBlue () / 65535.0f; a = gs->optionGetTabBaseColorAlpha () / 65535.0f; cairo_pattern_add_color_stop_rgba (pattern, 0.0f, r, g, b, a); /* highlight color */ r = gs->optionGetTabHighlightColorRed () / 65535.0f; g = gs->optionGetTabHighlightColorGreen () / 65535.0f; b = gs->optionGetTabHighlightColorBlue () / 65535.0f; a = gs->optionGetTabHighlightColorAlpha () / 65535.0f; cairo_pattern_add_color_stop_rgba (pattern, 0.55f, r, g, b, a); /* base color #2 */ r = gs->optionGetTabBaseColorRed () / 65535.0f; g = gs->optionGetTabBaseColorGreen () / 65535.0f; b = gs->optionGetTabBaseColorBlue () / 65535.0f; a = gs->optionGetTabBaseColorAlpha () / 65535.0f; cairo_pattern_add_color_stop_rgba (pattern, 1.0f, r, g, b, a); cairo_set_source (cr, pattern); cairo_fill_preserve (cr); cairo_pattern_destroy (pattern); break; } case GroupOptions::TabStyleMurrina: { double ratio, transX; cairo_pattern_t *pattern; cairo_save (cr); /* clip width rounded rectangle */ cairo_clip_preserve (cr); /* ==== TOP ==== */ x0 = borderWidth / 2.0; y0 = borderWidth / 2.0; x1 = twidth - borderWidth / 2.0; y1 = theight - borderWidth / 2.0; radius = (y1 - y0) / 2; /* setup pattern */ pattern = cairo_pattern_create_linear (0, 0, 0, theight); /* we don't want to use a full highlight here so we mix the colors */ r = (gs->optionGetTabHighlightColorRed () + gs->optionGetTabBaseColorRed ()) / (2 * 65535.0f); g = (gs->optionGetTabHighlightColorGreen () + gs->optionGetTabBaseColorGreen ()) / (2 * 65535.0f); b = (gs->optionGetTabHighlightColorBlue () + gs->optionGetTabBaseColorBlue ()) / (2 * 65535.0f); a = (gs->optionGetTabHighlightColorAlpha () + gs->optionGetTabBaseColorAlpha ()) / (2 * 65535.0f); cairo_pattern_add_color_stop_rgba (pattern, 0.0f, r, g, b, a); /* highlight color */ r = gs->optionGetTabHighlightColorRed () / 65535.0f; g = gs->optionGetTabHighlightColorGreen () / 65535.0f; b = gs->optionGetTabHighlightColorBlue () / 65535.0f; a = gs->optionGetTabHighlightColorAlpha () / 65535.0f; cairo_pattern_add_color_stop_rgba (pattern, 1.0f, r, g, b, a); cairo_set_source (cr, pattern); cairo_fill (cr); cairo_pattern_destroy (pattern); /* ==== BOTTOM ===== */ x0 = borderWidth / 2.0; y0 = borderWidth / 2.0; x1 = twidth - borderWidth / 2.0; y1 = theight - borderWidth / 2.0; radius = (y1 - y0) / 2; ratio = (double)twidth / (double)theight; transX = twidth - (twidth * ratio); cairo_move_to (cr, x1, y1); cairo_line_to (cr, x1, y0); if (twidth < theight) { cairo_translate (cr, transX, 0); cairo_scale (cr, ratio, 1.0); } cairo_arc (cr, x1 - radius, y0, radius, 0.0, M_PI * 0.5); if (twidth < theight) { cairo_scale (cr, 1.0 / ratio, 1.0); cairo_translate (cr, -transX, 0); cairo_scale (cr, ratio, 1.0); } cairo_arc_negative (cr, x0 + radius, y1, radius, M_PI * 1.5, M_PI); cairo_close_path (cr); /* setup pattern */ pattern = cairo_pattern_create_linear (0, 0, 0, theight); /* base color */ r = gs->optionGetTabBaseColorRed () / 65535.0f; g = gs->optionGetTabBaseColorGreen () / 65535.0f; b = gs->optionGetTabBaseColorBlue () / 65535.0f; a = gs->optionGetTabBaseColorAlpha () / 65535.0f; cairo_pattern_add_color_stop_rgba (pattern, 0.0f, r, g, b, a); /* we don't want to use a full highlight here so we mix the colors */ r = (gs->optionGetTabHighlightColorRed () + gs->optionGetTabBaseColorRed ()) / (2 * 65535.0f); g = (gs->optionGetTabHighlightColorGreen () + gs->optionGetTabBaseColorGreen ()) / (2 * 65535.0f); b = (gs->optionGetTabHighlightColorBlue () + gs->optionGetTabBaseColorBlue ()) / (2 * 65535.0f); a = (gs->optionGetTabHighlightColorAlpha () + gs->optionGetTabBaseColorAlpha ()) / (2 * 65535.0f); cairo_pattern_add_color_stop_rgba (pattern, 1.0f, r, g, b, a); cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); cairo_set_source (cr, pattern); cairo_fill (cr); cairo_pattern_destroy (pattern); cairo_set_operator (cr, CAIRO_OPERATOR_OVER); cairo_restore (cr); /* draw shape again for the outline */ x0 = borderWidth / 2.0; y0 = borderWidth / 2.0; x1 = twidth - borderWidth / 2.0; y1 = theight - borderWidth / 2.0; radius = gs->optionGetBorderRadius (); cairo_move_to (cr, x0 + radius, y0); cairo_arc (cr, x1 - radius, y0 + radius, radius, M_PI * 1.5, M_PI * 2.0); cairo_arc (cr, x1 - radius, y1 - radius, radius, 0.0, M_PI * 0.5); cairo_arc (cr, x0 + radius, y1 - radius, radius, M_PI * 0.5, M_PI); cairo_arc (cr, x0 + radius, y0 + radius, radius, M_PI, M_PI * 1.5); break; } default: break; } /* outline */ r = gs->optionGetTabBorderColorRed () / 65535.0f; g = gs->optionGetTabBorderColorGreen () / 65535.0f; b = gs->optionGetTabBorderColorBlue () / 65535.0f; a = gs->optionGetTabBorderColorAlpha () / 65535.0f; cairo_set_source_rgba (cr, r, g, b, a); /* If there is an animation running, stroke preserved * so that we can paint directly on top (and blend!) * the new animation with the existing tab bar. * Otherwise just stroke normally, this is less expensive */ if (mBgAnimation != AnimationNone) cairo_stroke_preserve (cr); else cairo_stroke (cr); /* There are two animations here: * Pulse: Highlight tab bar in and out (used for tab hover) * Reflex: Paint a diagonal gradient moving from right to left * on the tab bar when it appears */ switch (mBgAnimation) { case AnimationPulse: { double animationProgress; double alpha; /* Progress here is measured in the current time */ animationProgress = mBgAnimationTime / (gs->optionGetPulseTime () * 1000.0); /* The highlight pulsates in and out, so the alpha here should run * on a sine wave */ alpha = sin ((2 * PI * animationProgress) - 1.55)*0.5 + 0.5; /* If the alpha of the animation is < 0, don't bother painting */ if (alpha <= 0) break; cairo_save (cr); cairo_clip (cr); /* Paint highlight over the tab bar */ cairo_set_operator (cr, CAIRO_OPERATOR_XOR); cairo_rectangle (cr, 0.0, 0.0, twidth, theight); cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, alpha); cairo_fill (cr); cairo_restore (cr); break; } case AnimationReflex: { double animationProgress; double reflexWidth; double posX, alpha; cairo_pattern_t *pattern; /* Progress is measured in current time */ animationProgress = mBgAnimationTime / (gs->optionGetReflexTime () * 1000.0); /* Position here is the tab bar width plus the reflection width * 2 */ reflexWidth = (mGroup->mTabBar->mSlots.size () / 2.0) * 30; posX = (twidth + reflexWidth * 2.0) * animationProgress; alpha = sin (PI * animationProgress) * 0.55; if (alpha <= 0) break; cairo_save (cr); cairo_clip (cr); pattern = cairo_pattern_create_linear (posX - reflexWidth, 0.0, posX, theight); cairo_pattern_add_color_stop_rgba (pattern, 0.0f, 1.0, 1.0, 1.0, 0.0); cairo_pattern_add_color_stop_rgba (pattern, 0.5f, 1.0, 1.0, 1.0, alpha); cairo_pattern_add_color_stop_rgba (pattern, 1.0f, 1.0, 1.0, 1.0, 0.0); cairo_rectangle (cr, 0.0, 0.0, twidth, theight); cairo_set_source (cr, pattern); cairo_fill (cr); cairo_restore (cr); cairo_pattern_destroy (pattern); break; } case AnimationNone: default: break; } /* draw inner outline */ cairo_move_to (cr, x0 + radius + 1.0, y0 + 1.0); cairo_arc (cr, x1 - radius - 1.0, y0 + radius + 1.0, radius, M_PI * 1.5, M_PI * 2.0); cairo_arc (cr, x1 - radius - 1.0, y1 - radius - 1.0, radius, 0.0, M_PI * 0.5); cairo_arc (cr, x0 + radius + 1.0, y1 - radius - 1.0, radius, M_PI * 0.5, M_PI); cairo_arc (cr, x0 + radius + 1.0, y0 + radius + 1.0, radius, M_PI, M_PI * 1.5); cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.3); cairo_stroke(cr); cairo_restore (cr); mTexture = GLTexture::imageBufferToTexture ((char*) mBuffer, (CompSize &) *this); }
/* * groupAddWindowToGroup * */ void groupAddWindowToGroup (CompWindow *w, GroupSelection *group, long int initialIdent) { GROUP_SCREEN (w->screen); GROUP_WINDOW (w); if (gw->group) return; if (group) { CompWindow *topTab = NULL; group->windows = realloc (group->windows, sizeof (CompWindow *) * (group->nWins + 1)); group->windows[group->nWins] = w; group->nWins++; gw->group = group; updateWindowOutputExtents (w); groupUpdateWindowProperty (w); if (group->nWins == 2) { /* first window in the group got its glow, too */ updateWindowOutputExtents (group->windows[0]); } if (group->tabBar) { if (HAS_TOP_WIN (group)) topTab = TOP_TAB (group); else if (HAS_PREV_TOP_WIN (group)) { topTab = PREV_TOP_TAB (group); group->topTab = group->prevTopTab; group->prevTopTab = NULL; } if (topTab) { if (!gw->slot) groupCreateSlot (group, w); gw->destination.x = WIN_CENTER_X (topTab) - (WIN_WIDTH (w) / 2); gw->destination.y = WIN_CENTER_Y (topTab) - (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->xVelocity = gw->yVelocity = 0.0f; gw->animateState = IS_ANIMATED; groupStartTabbingAnimation (group, TRUE); addWindowDamage (w); } } } else { /* create new group */ GroupSelection *g = malloc (sizeof (GroupSelection)); if (!g) return; g->windows = malloc (sizeof (CompWindow *)); if (!g->windows) { free (g); return; } g->windows[0] = w; g->screen = w->screen; g->nWins = 1; g->topTab = NULL; g->prevTopTab = NULL; g->nextTopTab = NULL; g->changeAnimationTime = 0; g->changeAnimationDirection = 0; g->changeState = NoTabChange; g->tabbingState = NoTabbing; g->ungroupState = UngroupNone; g->tabBar = NULL; g->checkFocusAfterTabChange = FALSE; g->grabWindow = None; g->grabMask = 0; g->inputPrevention = None; g->ipwMapped = FALSE; /* glow color */ g->color[0] = (int)(rand () / (((double)RAND_MAX + 1) / 0xffff)); g->color[1] = (int)(rand () / (((double)RAND_MAX + 1) / 0xffff)); g->color[2] = (int)(rand () / (((double)RAND_MAX + 1) / 0xffff)); g->color[3] = 0xffff; if (initialIdent) g->identifier = initialIdent; else { /* we got no valid group Id passed, so find out a new valid unique one */ GroupSelection *tg; Bool invalidID = FALSE; g->identifier = gs->groups ? gs->groups->identifier : 0; do { invalidID = FALSE; for (tg = gs->groups; tg; tg = tg->next) { if (tg->identifier == g->identifier) { invalidID = TRUE; g->identifier++; break; } } } while (invalidID); } /* relink stack */ if (gs->groups) gs->groups->prev = g; g->next = gs->groups; g->prev = NULL; gs->groups = g; gw->group = g; groupUpdateWindowProperty (w); } }
void groupRemoveWindowFromGroup (CompWindow *w) { GROUP_WINDOW (w); if (!gw->group) return; if (gw->group->tabBar && !(gw->animateState & IS_UNGROUPING) && (gw->group->nWins > 1)) { GroupSelection *group = gw->group; /* if the group is tabbed, setup untabbing animation. The window will be deleted from the group at the end of the untabbing. */ if (HAS_TOP_WIN (group)) { CompWindow *tw = TOP_TAB (group); int oldX = gw->orgPos.x; int oldY = gw->orgPos.y; gw->orgPos.x = WIN_CENTER_X (tw) - (WIN_WIDTH (w) / 2); gw->orgPos.y = WIN_CENTER_Y (tw) - (WIN_HEIGHT (w) / 2); gw->destination.x = gw->orgPos.x + gw->mainTabOffset.x; gw->destination.y = gw->orgPos.y + gw->mainTabOffset.y; gw->mainTabOffset.x = oldX; gw->mainTabOffset.y = oldY; if (gw->tx || gw->ty) { gw->tx -= (gw->orgPos.x - oldX); gw->ty -= (gw->orgPos.y - oldY); } gw->animateState = IS_ANIMATED; 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 removed. */ groupStartTabbingAnimation (group, FALSE); groupSetWindowVisibility (w, TRUE); group->ungroupState = UngroupSingle; gw->animateState |= IS_UNGROUPING; } else { /* no tab bar - delete immediately */ groupDeleteGroupWindow (w); const BananaValue * option_autotab_create = bananaGetOption (bananaIndex, "autotab_create", w->screen->screenNum); if (option_autotab_create->b && groupIsGroupWindow (w)) { groupAddWindowToGroup (w, NULL, 0); groupTabGroup (w); } } }
/* * groupHandleButtonReleaseEvent * */ static void groupHandleButtonReleaseEvent (CompScreen *s, XEvent *event) { GroupSelection *group; int vx, vy; Region newRegion; Bool inserted = FALSE; Bool wasInTabBar = FALSE; GROUP_SCREEN (s); if (event->xbutton.button != 1) return; 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); newRegion = XCreateRegion (); if (!newRegion) return; XUnionRegion (newRegion, gs->draggedSlot->region, newRegion); groupGetDrawOffsetForSlot (gs->draggedSlot, &vx, &vy); XOffsetRegion (newRegion, vx, vy); for (group = gs->groups; group; group = group->next) { Bool inTabBar; Region clip, buf; GroupTabBarSlot *slot; if (!group->tabBar || !HAS_TOP_WIN (group)) continue; /* create clipping region */ clip = groupGetClippingRegion (TOP_TAB (group)); if (!clip) continue; buf = XCreateRegion (); if (!buf) { XDestroyRegion (clip); continue; } XIntersectRegion (newRegion, group->tabBar->region, buf); XSubtractRegion (buf, clip, buf); XDestroyRegion (clip); inTabBar = !XEmptyRegion (buf); XDestroyRegion (buf); if (!inTabBar) continue; wasInTabBar = TRUE; for (slot = group->tabBar->slots; slot; slot = slot->next) { GroupTabBarSlot *tmpDraggedSlot; GroupSelection *tmpGroup; Region slotRegion, buf; XRectangle rect; Bool inSlot; if (slot == gs->draggedSlot) continue; slotRegion = XCreateRegion (); if (!slotRegion) continue; 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); buf = XCreateRegion (); if (!buf) continue; XIntersectRegion (newRegion, slotRegion, buf); inSlot = !XEmptyRegion (buf); XDestroyRegion (buf); XDestroyRegion (slotRegion); if (!inSlot) continue; tmpDraggedSlot = gs->draggedSlot; if (group != gw->group) { CompWindow *w = gs->draggedSlot->window; GroupSelection *tmpGroup = gw->group; int oldPosX = WIN_CENTER_X (w); int oldPosY = WIN_CENTER_Y (w); /* if the dragged window is not the top tab, move it onscreen */ if (tmpGroup->topTab && !IS_TOP_TAB (w, tmpGroup)) { CompWindow *tw = TOP_TAB (tmpGroup); oldPosX = WIN_CENTER_X (tw) + gw->mainTabOffset.x; oldPosY = WIN_CENTER_Y (tw) + gw->mainTabOffset.y; groupSetWindowVisibility (w, TRUE); } /* Change the group. */ groupDeleteGroupWindow (gs->draggedSlot->window); groupAddWindowToGroup (gs->draggedSlot->window, group, 0); /* we saved the original center position in oldPosX/Y before - now we should apply that to the new main tab offset */ if (HAS_TOP_WIN (group)) { CompWindow *tw = TOP_TAB (group); gw->mainTabOffset.x = oldPosX - WIN_CENTER_X (tw); gw->mainTabOffset.y = oldPosY - WIN_CENTER_Y (tw); } } else groupUnhookTabBarSlot (group->tabBar, gs->draggedSlot, TRUE); 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); groupDamageTabBarRegion (group); /* Hide tab-bars. */ for (tmpGroup = gs->groups; tmpGroup; tmpGroup = tmpGroup->next) { if (group == tmpGroup) groupTabSetVisibility (tmpGroup, TRUE, 0); else groupTabSetVisibility (tmpGroup, FALSE, PERMANENT); } break; } if (inserted) break; } 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; const BananaValue * option_dnd_ungroup_window = bananaGetOption (bananaIndex, "dnd_ungroup_window", s->screenNum); if (option_dnd_ungroup_window->b && !wasInTabBar) { groupRemoveWindowFromGroup (draggedSlotWindow); } 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; } }