~ubuntu-branches/ubuntu/lucid/compiz-fusion-plugins-extra/lucid

« back to all changes in this revision

Viewing changes to src/group/tab.c

  • Committer: Bazaar Package Importer
  • Author(s): Michael Vogt
  • Date: 2007-12-05 22:48:25 UTC
  • mfrom: (1.1.15 upstream)
  • Revision ID: james.westby@ubuntu.com-20071205224825-yhfs0zm2evj7ca3x
Tags: 0.6.99+git20071127-0ubuntu1
new git HEAD snapshot

Show diffs side-by-side

added added

removed removed

Lines of Context:
34
34
 */
35
35
Bool
36
36
groupGetCurrentMousePosition (CompScreen *s,
37
 
                                                          int        *x,
38
 
                                                          int        *y)
 
37
                              int        *x,
 
38
                              int        *y)
39
39
{
40
 
        unsigned int rmask;
41
 
        int          mouseX, mouseY, winX, winY;
42
 
        Window       root;
43
 
        Window       child;
44
 
        Bool         result;
45
 
 
46
 
        result = XQueryPointer (s->display->display, s->root, &root,
47
 
                                                        &child, &mouseX, &mouseY, &winX, &winY, &rmask);
48
 
 
49
 
        if (result)
50
 
        {
51
 
                (*x) = mouseX;
52
 
                (*y) = mouseY;
53
 
        }
54
 
 
55
 
        return result;
 
40
    unsigned int rmask;
 
41
    int          mouseX, mouseY, winX, winY;
 
42
    Window       root;
 
43
    Window       child;
 
44
    Bool         result;
 
45
 
 
46
    result = XQueryPointer (s->display->display, s->root, &root,
 
47
                            &child, &mouseX, &mouseY, &winX, &winY, &rmask);
 
48
 
 
49
    if (result)
 
50
    {
 
51
        (*x) = mouseX;
 
52
        (*y) = mouseY;
 
53
    }
 
54
 
 
55
    return result;
56
56
}
57
57
 
58
58
/*
71
71
Region
72
72
groupGetClippingRegion (CompWindow *w)
73
73
{
74
 
        CompWindow *cw;
75
 
        Region     clip;
76
 
        
77
 
        clip = XCreateRegion();
78
 
        if (!clip)
 
74
    CompWindow *cw;
 
75
    Region     clip;
 
76
 
 
77
    clip = XCreateRegion ();
 
78
    if (!clip)
 
79
        return NULL;
 
80
 
 
81
    for (cw = w->next; cw; cw = cw->next)
 
82
    {
 
83
        if (!cw->invisible && !(cw->state & CompWindowStateHiddenMask))
 
84
        {
 
85
            XRectangle rect;
 
86
            Region     buf;
 
87
 
 
88
            buf = XCreateRegion ();
 
89
            if (!buf)
 
90
            {
 
91
                XDestroyRegion (clip);
79
92
                return NULL;
80
 
 
81
 
        for (cw = w->next; cw; cw = cw->next)
82
 
        {
83
 
                if (!cw->invisible && !(cw->state & CompWindowStateHiddenMask))
84
 
                {
85
 
                        XRectangle rect;
86
 
                        Region     buf;
87
 
                        
88
 
                        buf = XCreateRegion();
89
 
                        if (!buf)
90
 
                        {
91
 
                                XDestroyRegion(clip);
92
 
                                return NULL;
93
 
                        }
94
 
 
95
 
                        rect.x = WIN_REAL_X (cw);
96
 
                        rect.y = WIN_REAL_Y (cw);
97
 
                        rect.width = WIN_REAL_WIDTH (cw);
98
 
                        rect.height = WIN_REAL_HEIGHT (cw);
99
 
                        XUnionRectWithRegion (&rect, buf, buf);
100
 
 
101
 
                        XUnionRegion (clip, buf, clip);
102
 
                        XDestroyRegion (buf);
103
 
                }
 
93
            }
 
94
 
 
95
            rect.x      = WIN_REAL_X (cw);
 
96
            rect.y      = WIN_REAL_Y (cw);
 
97
            rect.width  = WIN_REAL_WIDTH (cw);
 
98
            rect.height = WIN_REAL_HEIGHT (cw);
 
99
            XUnionRectWithRegion (&rect, buf, buf);
 
100
 
 
101
            XUnionRegion (clip, buf, clip);
 
102
            XDestroyRegion (buf);
104
103
        }
 
104
    }
105
105
 
106
 
        return clip;
 
106
    return clip;
107
107
}
108
108
 
109
109
 
113
113
 */
114
114
void
115
115
groupClearWindowInputShape (CompWindow          *w,
116
 
                                                        GroupWindowHideInfo *hideInfo)
 
116
                            GroupWindowHideInfo *hideInfo)
117
117
{
118
 
        XRectangle *rects;
119
 
        int        count, ordering;
120
 
 
121
 
        rects = XShapeGetRectangles (w->screen->display->display,
122
 
                                                                 w->id, ShapeInput, &count, &ordering);
123
 
 
124
 
        if (count == 0)
125
 
        {
126
 
                XFree (rects);
127
 
                return;
128
 
        }
129
 
 
130
 
        /* check if the returned shape exactly matches the window shape -
131
 
           if that is true, the window currently has no set input shape */
132
 
        if ((count == 1) &&
133
 
                (rects[0].x == -w->serverBorderWidth) &&
134
 
                (rects[0].y == -w->serverBorderWidth) &&
135
 
                (rects[0].width == (w->serverWidth + w->serverBorderWidth)) &&
136
 
                (rects[0].height == (w->serverHeight + w->serverBorderWidth)))
137
 
        {
138
 
                count = 0;
139
 
        }
140
 
 
141
 
        if (hideInfo->inputRects)
142
 
                XFree (hideInfo->inputRects);
143
 
 
144
 
        hideInfo->inputRects = rects;
145
 
        hideInfo->nInputRects = count;
146
 
        hideInfo->inputRectOrdering = ordering;
147
 
 
148
 
        XShapeSelectInput (w->screen->display->display, w->id, NoEventMask);
149
 
 
150
 
        XShapeCombineRectangles (w->screen->display->display, w->id,
151
 
                                                         ShapeInput, 0, 0, NULL, 0, ShapeSet, 0);
152
 
 
153
 
        XShapeSelectInput (w->screen->display->display, w->id, ShapeNotify);
 
118
    XRectangle  *rects;
 
119
    int         count = 0, ordering;
 
120
    CompDisplay *d = w->screen->display;
 
121
 
 
122
    rects = XShapeGetRectangles (d->display, w->id, ShapeInput,
 
123
                                 &count, &ordering);
 
124
 
 
125
    if (count == 0)
 
126
        return;
 
127
 
 
128
    /* check if the returned shape exactly matches the window shape -
 
129
       if that is true, the window currently has no set input shape */
 
130
    if ((count == 1) &&
 
131
        (rects[0].x == -w->serverBorderWidth) &&
 
132
        (rects[0].y == -w->serverBorderWidth) &&
 
133
        (rects[0].width == (w->serverWidth + w->serverBorderWidth)) &&
 
134
        (rects[0].height == (w->serverHeight + w->serverBorderWidth)))
 
135
    {
 
136
        count = 0;
 
137
    }
 
138
 
 
139
    if (hideInfo->inputRects)
 
140
        XFree (hideInfo->inputRects);
 
141
 
 
142
    hideInfo->inputRects = rects;
 
143
    hideInfo->nInputRects = count;
 
144
    hideInfo->inputRectOrdering = ordering;
 
145
 
 
146
    XShapeSelectInput (d->display, w->id, NoEventMask);
 
147
 
 
148
    XShapeCombineRectangles (d->display, w->id, ShapeInput, 0, 0,
 
149
                             NULL, 0, ShapeSet, 0);
 
150
 
 
151
    XShapeSelectInput (d->display, w->id, ShapeNotify);
154
152
}
155
153
 
156
154
/*
159
157
 */
160
158
void
161
159
groupSetWindowVisibility (CompWindow *w,
162
 
                                                  Bool       visible)
 
160
                          Bool       visible)
163
161
{
164
 
        GROUP_WINDOW (w);
165
 
 
166
 
        if (!visible && !gw->windowHideInfo)
167
 
        {
168
 
                GroupWindowHideInfo *info;
169
 
 
170
 
                gw->windowHideInfo = info = malloc (sizeof (GroupWindowHideInfo));
171
 
                if (!gw->windowHideInfo)
172
 
                        return;
173
 
 
174
 
                info->inputRects = NULL;
175
 
                info->nInputRects = 0;
176
 
                info->shapeMask = XShapeInputSelected (w->screen->display->display,
177
 
                                                                                           w->id);
178
 
                groupClearWindowInputShape (w, info);
179
 
 
180
 
                if (w->frame)
181
 
                {
182
 
                        info->frameWindow = w->frame;
183
 
                        XUnmapWindow (w->screen->display->display, w->frame);
184
 
                } else
185
 
                        info->frameWindow = None;
186
 
 
187
 
                info->skipState = w->state & (CompWindowStateSkipPagerMask |
188
 
                                                                          CompWindowStateSkipTaskbarMask);
189
 
 
190
 
                changeWindowState (w,
191
 
                                                   w->state | CompWindowStateSkipPagerMask |
192
 
                                                   CompWindowStateSkipTaskbarMask);
193
 
        }
194
 
        else if (visible && gw->windowHideInfo)
195
 
        {
196
 
                GroupWindowHideInfo *info = gw->windowHideInfo;
197
 
 
198
 
                if (info->nInputRects)
199
 
                {
200
 
                        XShapeCombineRectangles (w->screen->display->display,
201
 
                                                                         w->id, ShapeInput, 0, 0,
202
 
                                                                         info->inputRects,
203
 
                                                                         info->nInputRects,
204
 
                                                                         ShapeSet,
205
 
                                                                         info->inputRectOrdering);
206
 
                }
207
 
                else
208
 
                {
209
 
                        XShapeCombineMask (w->screen->display->display, w->id,
210
 
                                                           ShapeInput, 0, 0, None, ShapeSet);
211
 
                }
212
 
 
213
 
                if (info->inputRects)
214
 
                        XFree (info->inputRects);
215
 
 
216
 
                XShapeSelectInput (w->screen->display->display, w->id,
217
 
                                                   info->shapeMask);
218
 
 
219
 
                if (info->frameWindow)
220
 
                {
221
 
                        if (w->attrib.map_state != IsUnmapped)
222
 
                                XMapWindow (w->screen->display->display, w->frame);
223
 
                }
224
 
 
225
 
                changeWindowState (w,
226
 
                                                   (w->state & ~(CompWindowStateSkipPagerMask |
227
 
                                                                                 CompWindowStateSkipTaskbarMask)) |
228
 
                                                   info->skipState);
229
 
 
230
 
                free (info);
231
 
                gw->windowHideInfo = NULL;
232
 
        }
 
162
    CompDisplay *d = w->screen->display;
 
163
 
 
164
    GROUP_WINDOW (w);
 
165
 
 
166
    if (!visible && !gw->windowHideInfo)
 
167
    {
 
168
        GroupWindowHideInfo *info;
 
169
 
 
170
        gw->windowHideInfo = info = malloc (sizeof (GroupWindowHideInfo));
 
171
        if (!gw->windowHideInfo)
 
172
            return;
 
173
 
 
174
        info->inputRects = NULL;
 
175
        info->nInputRects = 0;
 
176
        info->shapeMask = XShapeInputSelected (d->display, w->id);
 
177
        groupClearWindowInputShape (w, info);
 
178
 
 
179
        if (w->frame)
 
180
        {
 
181
            info->frameWindow = w->frame;
 
182
            XUnmapWindow (d->display, w->frame);
 
183
        } else
 
184
            info->frameWindow = None;
 
185
 
 
186
        info->skipState = w->state & (CompWindowStateSkipPagerMask |
 
187
                                      CompWindowStateSkipTaskbarMask);
 
188
 
 
189
        changeWindowState (w, w->state |
 
190
                           CompWindowStateSkipPagerMask |
 
191
                           CompWindowStateSkipTaskbarMask);
 
192
    }
 
193
    else if (visible && gw->windowHideInfo)
 
194
    {
 
195
        GroupWindowHideInfo *info = gw->windowHideInfo;
 
196
 
 
197
        if (info->nInputRects)
 
198
        {
 
199
            XShapeCombineRectangles (d->display, w->id, ShapeInput, 0, 0,
 
200
                                     info->inputRects, info->nInputRects,
 
201
                                     ShapeSet, info->inputRectOrdering);
 
202
        }
 
203
        else
 
204
        {
 
205
            XShapeCombineMask (d->display, w->id, ShapeInput,
 
206
                               0, 0, None, ShapeSet);
 
207
        }
 
208
 
 
209
        if (info->inputRects)
 
210
            XFree (info->inputRects);
 
211
 
 
212
        XShapeSelectInput (d->display, w->id, info->shapeMask);
 
213
 
 
214
        if (info->frameWindow)
 
215
        {
 
216
            if (w->attrib.map_state != IsUnmapped)
 
217
                XMapWindow (d->display, w->frame);
 
218
        }
 
219
 
 
220
        changeWindowState (w,
 
221
                           (w->state & ~(CompWindowStateSkipPagerMask |
 
222
                                         CompWindowStateSkipTaskbarMask)) |
 
223
                           info->skipState);
 
224
 
 
225
        free (info);
 
226
        gw->windowHideInfo = NULL;
 
227
    }
233
228
}
234
229
 
235
230
/*
240
235
 * We use this to realize a delay with the bar hiding after tab change.
241
236
 * groupHandleAnimation sets up a timer after the animation has finished.
242
237
 * This function itself basically just sets the tab bar to a PaintOff status
243
 
 * through calling groupSetTabBarVisibility. The PERMANENT mask allows you to fore
244
 
 * a hiding of even PaintPermanentOn tab bars.
 
238
 * through calling groupSetTabBarVisibility.
 
239
 * The PERMANENT mask allows you to force hiding even of
 
240
 * PaintPermanentOn tab bars.
245
241
 *
246
242
 */
247
243
static Bool
248
244
groupTabBarTimeout (void *data)
249
245
{
250
 
        GroupSelection *group = (GroupSelection *) data;
251
 
 
252
 
        groupTabSetVisibility (group, FALSE, PERMANENT);
253
 
 
254
 
        group->tabBar->timeoutHandle = 0;
255
 
 
256
 
        return FALSE;   /* This will free the timer. */
 
246
    GroupSelection *group = (GroupSelection *) data;
 
247
 
 
248
    groupTabSetVisibility (group, FALSE, PERMANENT);
 
249
 
 
250
    group->tabBar->timeoutHandle = 0;
 
251
 
 
252
    return FALSE;       /* This will free the timer. */
257
253
}
258
254
 
259
255
/*
263
259
static Bool
264
260
groupShowDelayTimeout (void *data)
265
261
{
266
 
        int            mouseX, mouseY;
267
 
        GroupSelection *group = (GroupSelection *) data;
268
 
        CompScreen     *s = group->screen;
269
 
        CompWindow     *topTab;
270
 
 
271
 
        GROUP_SCREEN (s);
272
 
 
273
 
        if (!HAS_TOP_WIN (group))
274
 
        {
275
 
                gs->showDelayTimeoutHandle = 0;
276
 
                return FALSE;   /* This will free the timer. */
277
 
        }
278
 
 
279
 
        topTab = group->topTab->window;
280
 
 
281
 
        groupGetCurrentMousePosition (s, &mouseX, &mouseY);
282
 
 
283
 
        groupRecalcTabBarPos (group, mouseX, WIN_REAL_X (topTab),
284
 
                                                  WIN_REAL_X (topTab) + WIN_REAL_WIDTH (topTab));
285
 
 
286
 
        groupTabSetVisibility (group, TRUE, 0);
287
 
 
 
262
    int            mouseX, mouseY;
 
263
    GroupSelection *group = (GroupSelection *) data;
 
264
    CompScreen     *s = group->screen;
 
265
    CompWindow     *topTab;
 
266
 
 
267
    GROUP_SCREEN (s);
 
268
 
 
269
    if (!HAS_TOP_WIN (group))
 
270
    {
288
271
        gs->showDelayTimeoutHandle = 0;
289
272
        return FALSE;   /* This will free the timer. */
290
 
}
291
 
 
292
 
/*
293
 
 * groupCheckForVisibleTabBars
294
 
 *
295
 
 * Description:
296
 
 * This function is used to update the gs->tabBarVisible
297
 
 * attribute which is used in groupPaintOutput to do add
298
 
 * a PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MAS mask to the
299
 
 * screen mask. It checks if there are any tab bar's with
300
 
 * a PaintState which is no PaintOff on the given screen.
301
 
 *
302
 
 */
303
 
void
304
 
groupCheckForVisibleTabBars (CompScreen *s)
305
 
{
306
 
        GroupSelection *group;
307
 
 
308
 
        GROUP_SCREEN (s);
309
 
 
310
 
        gs->tabBarVisible = FALSE;
311
 
 
312
 
        for (group = gs->groups; group; group = group->next)
313
 
        {
314
 
                if (group->tabBar && (group->tabBar->state != PaintOff))
315
 
                {
316
 
                        gs->tabBarVisible = TRUE;
317
 
                        break;
318
 
                }
319
 
        }
 
273
    }
 
274
 
 
275
    topTab = TOP_TAB (group);
 
276
 
 
277
    groupGetCurrentMousePosition (s, &mouseX, &mouseY);
 
278
 
 
279
    groupRecalcTabBarPos (group, mouseX, WIN_REAL_X (topTab),
 
280
                          WIN_REAL_X (topTab) + WIN_REAL_WIDTH (topTab));
 
281
 
 
282
    groupTabSetVisibility (group, TRUE, 0);
 
283
 
 
284
    gs->showDelayTimeoutHandle = 0;
 
285
    return FALSE;       /* This will free the timer. */
320
286
}
321
287
 
322
288
/*
331
297
 * This mask affects how the visible parameter is handled, for example if
332
298
 * visibule is set to TRUE and the mask to PERMANENT state it will set
333
299
 * PaintPermanentOn state for the tab bar. When visibile is FALSE, mask 0
334
 
 * and the current state of the tab bar is PaintPermanentOn it won't do anything
335
 
 * because its not strong enough to disable a Permanent-State, for those you need
336
 
 * the mask.
 
300
 * and the current state of the tab bar is PaintPermanentOn it won't do
 
301
 * anything because its not strong enough to disable a
 
302
 * Permanent-State, for those you need the mask.
337
303
 *
338
304
 */
339
305
void
340
306
groupTabSetVisibility (GroupSelection *group,
341
 
                                           Bool           visible,
342
 
                                           unsigned int   mask)
 
307
                       Bool           visible,
 
308
                       unsigned int   mask)
343
309
{
344
 
        GroupTabBar *bar;
345
 
        CompWindow  *topTab;
346
 
        PaintState  oldState;
347
 
 
348
 
        if (!group || !group->windows || !group->tabBar || !HAS_TOP_WIN (group))
349
 
                return;
350
 
 
351
 
        bar = group->tabBar;
352
 
        topTab = TOP_TAB (group);
353
 
        oldState = bar->state;
354
 
 
355
 
        /* hide tab bars for invisible top windows */
356
 
        if ((topTab->state & CompWindowStateHiddenMask) || topTab->invisible)
357
 
        {
358
 
                bar->state = PaintOff;
359
 
                groupSwitchTopTabInput (group, TRUE);
360
 
        }
361
 
 
362
 
        else if (visible && bar->state != PaintPermanentOn &&
363
 
                         (mask & PERMANENT))
364
 
        {
365
 
                bar->state = PaintPermanentOn;
366
 
                groupSwitchTopTabInput (group, FALSE);
367
 
 
368
 
        }
369
 
 
370
 
        else if (visible && bar->state == PaintPermanentOn &&
371
 
                         !(mask & PERMANENT))
372
 
        {
373
 
                bar->state = PaintOn;
374
 
        }
375
 
 
376
 
        else if (visible &&
377
 
                         (bar->state == PaintOff || bar->state == PaintFadeOut))
378
 
        {
379
 
                if (groupGetBarAnimations (group->screen))
380
 
                {
381
 
                        bar->bgAnimation = AnimationReflex;
382
 
                        bar->bgAnimationTime = groupGetReflexTime (group->screen) * 1000.0;
383
 
                }
384
 
                bar->state = PaintFadeIn;
385
 
                groupSwitchTopTabInput (group, FALSE);
386
 
        }
387
 
 
388
 
        else if (!visible &&
389
 
                         (bar->state != PaintPermanentOn || (mask & PERMANENT)) &&
390
 
                         (bar->state == PaintOn || bar->state == PaintPermanentOn ||
391
 
                          bar->state == PaintFadeIn))
392
 
        {
393
 
                bar->state = PaintFadeOut;
394
 
                groupSwitchTopTabInput (group, TRUE);
395
 
        }
396
 
 
397
 
        if (bar->state == PaintFadeIn || bar->state == PaintFadeOut)
398
 
                bar->animationTime = (groupGetFadeTime (group->screen) * 1000) -
399
 
                                         bar->animationTime;
400
 
 
401
 
        if (bar->state != oldState)
402
 
                groupDamageTabBarRegion (group);
403
 
 
404
 
        groupCheckForVisibleTabBars (group->screen);
 
310
    GroupTabBar *bar;
 
311
    CompWindow  *topTab;
 
312
    PaintState  oldState;
 
313
    CompScreen  *s;
 
314
 
 
315
    if (!group || !group->windows || !group->tabBar || !HAS_TOP_WIN (group))
 
316
        return;
 
317
 
 
318
    s = group->screen;
 
319
    bar = group->tabBar;
 
320
    topTab = TOP_TAB (group);
 
321
    oldState = bar->state;
 
322
 
 
323
    /* hide tab bars for invisible top windows */
 
324
    if ((topTab->state & CompWindowStateHiddenMask) || topTab->invisible)
 
325
    {
 
326
        bar->state = PaintOff;
 
327
        groupSwitchTopTabInput (group, TRUE);
 
328
    }
 
329
    else if (visible && bar->state != PaintPermanentOn && (mask & PERMANENT))
 
330
    {
 
331
        bar->state = PaintPermanentOn;
 
332
        groupSwitchTopTabInput (group, FALSE);
 
333
    }
 
334
    else if (visible && bar->state == PaintPermanentOn && !(mask & PERMANENT))
 
335
    {
 
336
        bar->state = PaintOn;
 
337
    }
 
338
    else if (visible && (bar->state == PaintOff || bar->state == PaintFadeOut))
 
339
    {
 
340
        if (groupGetBarAnimations (s))
 
341
        {
 
342
            bar->bgAnimation = AnimationReflex;
 
343
            bar->bgAnimationTime = groupGetReflexTime (s) * 1000.0;
 
344
        }
 
345
        bar->state = PaintFadeIn;
 
346
        groupSwitchTopTabInput (group, FALSE);
 
347
    }
 
348
    else if (!visible &&
 
349
             (bar->state != PaintPermanentOn || (mask & PERMANENT)) &&
 
350
             (bar->state == PaintOn || bar->state == PaintPermanentOn ||
 
351
              bar->state == PaintFadeIn))
 
352
    {
 
353
        bar->state = PaintFadeOut;
 
354
        groupSwitchTopTabInput (group, TRUE);
 
355
    }
 
356
 
 
357
    if (bar->state == PaintFadeIn || bar->state == PaintFadeOut)
 
358
        bar->animationTime = (groupGetFadeTime (s) * 1000) - bar->animationTime;
 
359
 
 
360
    if (bar->state != oldState)
 
361
        groupDamageTabBarRegion (group);
405
362
}
406
363
 
407
364
/*
414
371
 */
415
372
void
416
373
groupGetDrawOffsetForSlot (GroupTabBarSlot *slot,
417
 
                                                   int             *hoffset,
418
 
                                                   int             *voffset)
 
374
                           int             *hoffset,
 
375
                           int             *voffset)
419
376
{
420
 
        CompWindow *w, *topTab;
421
 
        int        vx, vy, x, y;
422
 
 
423
 
        if (!slot || !slot->window)
424
 
                return;
425
 
 
426
 
        w = slot->window;
427
 
 
428
 
        GROUP_WINDOW (w);
429
 
        GROUP_SCREEN (w->screen);
430
 
 
431
 
        if (slot != gs->draggedSlot)
432
 
        {
433
 
                if (hoffset)
434
 
                        *hoffset = 0;
435
 
                if (voffset)
436
 
                        *voffset = 0;
437
 
 
438
 
                return;
439
 
        }
440
 
 
441
 
        if (HAS_TOP_WIN (gw->group))
442
 
                topTab = TOP_TAB (gw->group);
443
 
        else if (HAS_PREV_TOP_WIN (gw->group))
444
 
                topTab = PREV_TOP_TAB (gw->group);
445
 
        else
446
 
        {
447
 
                if (hoffset)
448
 
                        *hoffset = 0;
449
 
                if (voffset)
450
 
                        *voffset = 0;
451
 
                return;
452
 
        }
453
 
 
454
 
        x = WIN_X (topTab) + WIN_WIDTH (topTab) / 2 -
455
 
                WIN_WIDTH (w) / 2;
456
 
        y = WIN_Y (topTab) + WIN_HEIGHT (topTab) / 2 -
457
 
                WIN_HEIGHT (w) / 2;
458
 
 
459
 
        viewportForGeometry (w->screen, 
460
 
                                                 x, y, w->serverWidth, w->serverHeight,
461
 
                                                 w->serverBorderWidth,
462
 
                                                 &vx, &vy);
463
 
 
464
 
        if (hoffset)
465
 
                *hoffset = ((w->screen->x - vx) % w->screen->hsize) * w->screen->width;
466
 
 
467
 
        if (voffset)
468
 
                *voffset = ((w->screen->y - vy) % w->screen->vsize) * w->screen->height;
 
377
    CompWindow *w, *topTab;
 
378
    CompScreen *s;
 
379
    int        vx, vy, x, y;
 
380
 
 
381
    if (!slot || !slot->window)
 
382
        return;
 
383
 
 
384
    w = slot->window;
 
385
    s = w->screen;
 
386
 
 
387
    GROUP_WINDOW (w);
 
388
    GROUP_SCREEN (s);
 
389
 
 
390
    if (slot != gs->draggedSlot)
 
391
    {
 
392
        if (hoffset)
 
393
            *hoffset = 0;
 
394
        if (voffset)
 
395
            *voffset = 0;
 
396
 
 
397
        return;
 
398
    }
 
399
 
 
400
    if (HAS_TOP_WIN (gw->group))
 
401
        topTab = TOP_TAB (gw->group);
 
402
    else if (HAS_PREV_TOP_WIN (gw->group))
 
403
        topTab = PREV_TOP_TAB (gw->group);
 
404
    else
 
405
    {
 
406
        if (hoffset)
 
407
            *hoffset = 0;
 
408
        if (voffset)
 
409
            *voffset = 0;
 
410
        return;
 
411
    }
 
412
 
 
413
    x = WIN_CENTER_X (topTab) - WIN_WIDTH (w) / 2;
 
414
    y = WIN_CENTER_Y (topTab) - WIN_HEIGHT (w) / 2;
 
415
 
 
416
    viewportForGeometry (s, x, y, w->serverWidth, w->serverHeight,
 
417
                         w->serverBorderWidth, &vx, &vy);
 
418
 
 
419
    if (hoffset)
 
420
        *hoffset = ((s->x - vx) % s->hsize) * s->width;
 
421
 
 
422
    if (voffset)
 
423
        *voffset = ((s->y - vy) % s->vsize) * s->height;
469
424
}
470
425
 
471
426
/*
476
431
 * the hover detection. This is needed for the text showing up,
477
432
 * when you hover a thumb on the thumb bar.
478
433
 *
 
434
 * FIXME: we should better have a timer for that ...
479
435
 */
480
436
void
481
437
groupHandleHoverDetection (GroupSelection *group)
482
438
{
483
 
        GroupTabBar *bar = group->tabBar;
484
 
        CompWindow  *topTab;
485
 
 
486
 
        if (!HAS_TOP_WIN (group))
 
439
    GroupTabBar *bar = group->tabBar;
 
440
    CompWindow  *topTab = TOP_TAB (group);
 
441
    int         mouseX, mouseY;
 
442
    Bool        mouseOnScreen, inLastSlot;
 
443
 
 
444
    /* first get the current mouse position */
 
445
    mouseOnScreen = groupGetCurrentMousePosition (group->screen,
 
446
                                                  &mouseX, &mouseY);
 
447
 
 
448
    if (!mouseOnScreen)
 
449
        return;
 
450
 
 
451
    /* then check if the mouse is in the last hovered slot --
 
452
       this saves a lot of CPU usage */
 
453
    inLastSlot = bar->hoveredSlot &&
 
454
                 XPointInRegion (bar->hoveredSlot->region, mouseX, mouseY);
 
455
 
 
456
    if (!inLastSlot)
 
457
    {
 
458
        Region          clip;
 
459
        GroupTabBarSlot *slot;
 
460
 
 
461
        bar->hoveredSlot = NULL;
 
462
        clip = groupGetClippingRegion (topTab);
 
463
 
 
464
        for (slot = bar->slots; slot; slot = slot->next)
 
465
        {
 
466
            /* We need to clip the slot region with the clip region first.
 
467
               This is needed to respect the window stack, so if a window
 
468
               covers a port of that slot, this part won't be used
 
469
               for in-slot-detection. */
 
470
            Region reg = XCreateRegion();
 
471
            if (!reg)
 
472
            {
 
473
                XDestroyRegion(clip);
487
474
                return;
488
 
 
489
 
        topTab = TOP_TAB(group);
490
 
 
491
 
        if (bar->state != PaintOff)
 
475
            }
 
476
 
 
477
            XSubtractRegion (slot->region, clip, reg);
 
478
 
 
479
            if (XPointInRegion (reg, mouseX, mouseY))
 
480
            {
 
481
                bar->hoveredSlot = slot;
 
482
                XDestroyRegion (reg);
 
483
                break;
 
484
            }
 
485
 
 
486
            XDestroyRegion (reg);
 
487
        }
 
488
 
 
489
        XDestroyRegion (clip);
 
490
 
 
491
        if (bar->textLayer)
492
492
        {
493
 
                /* Tab-bar is visible. */
494
 
                int  mouseX, mouseY;
495
 
                Bool mouseOnScreen;
496
 
 
497
 
                /* first get the current mouse position */
498
 
                mouseOnScreen = groupGetCurrentMousePosition (group->screen,
499
 
                                                                                                          &mouseX, &mouseY);
500
 
 
501
 
                /* then check if the mouse is in the last hovered slot --
502
 
                   this saves a lot of CPU usage */
503
 
                if (mouseOnScreen &&
504
 
                        !(bar->hoveredSlot &&
505
 
                          XPointInRegion (bar->hoveredSlot->region, mouseX, mouseY)))
506
 
                {
507
 
                        Region          clip;
508
 
                        GroupTabBarSlot *slot;
509
 
 
510
 
                        bar->hoveredSlot = NULL;
511
 
                        clip = groupGetClippingRegion (topTab);
512
 
 
513
 
                        for (slot = bar->slots; slot; slot = slot->next)
514
 
                        {
515
 
                                /* We need to clip the slot region with the clip region first.
516
 
                                   This is needed to respect the window stack, so if a window
517
 
                                   covers a port of that slot, this part won't be used
518
 
                                   for in-slot-detection. */
519
 
                                Region reg = XCreateRegion();
520
 
                                if (!reg)
521
 
                                {
522
 
                                        XDestroyRegion(clip);
523
 
                                        return;
524
 
                                }
525
 
 
526
 
                                XSubtractRegion (slot->region, clip, reg);
527
 
 
528
 
                                if (XPointInRegion (reg, mouseX, mouseY))
529
 
                                {
530
 
                                        bar->hoveredSlot = slot;
531
 
                                        XDestroyRegion (reg);
532
 
                                        break;
533
 
                                }
534
 
 
535
 
                                XDestroyRegion (reg);
536
 
                        }
537
 
 
538
 
                        XDestroyRegion (clip);
539
 
 
540
 
                        if (bar->textLayer)
541
 
                        {
542
 
                                /* trigger a FadeOut of the text */
543
 
                                if ((bar->hoveredSlot != bar->textSlot) &&
544
 
                                        (bar->textLayer->state == PaintFadeIn ||
545
 
                                         bar->textLayer->state == PaintOn))
546
 
                                {
547
 
                                        bar->textLayer->animationTime =
548
 
                                                (groupGetFadeTextTime (group->screen) * 1000) -
549
 
                                                bar->textLayer->animationTime;
550
 
                                        bar->textLayer->state = PaintFadeOut;
551
 
                                }
552
 
 
553
 
                                // or trigger a FadeIn of the text
554
 
                                else if (bar->textLayer->state == PaintFadeOut &&
555
 
                                                 bar->hoveredSlot == bar->textSlot && bar->hoveredSlot)
556
 
                                {
557
 
                                        bar->textLayer->animationTime =
558
 
                                                (groupGetFadeTextTime (group->screen) * 1000) -
559
 
                                                bar->textLayer->animationTime;
560
 
                                        bar->textLayer->state = PaintFadeIn;
561
 
                                }
562
 
                        }
563
 
                }
 
493
            /* trigger a FadeOut of the text */
 
494
            if ((bar->hoveredSlot != bar->textSlot) &&
 
495
                (bar->textLayer->state == PaintFadeIn ||
 
496
                 bar->textLayer->state == PaintOn))
 
497
            {
 
498
                bar->textLayer->animationTime =
 
499
                    (groupGetFadeTextTime (group->screen) * 1000) -
 
500
                    bar->textLayer->animationTime;
 
501
                bar->textLayer->state = PaintFadeOut;
 
502
            }
 
503
 
 
504
            /* or trigger a FadeIn of the text */
 
505
            else if (bar->textLayer->state == PaintFadeOut &&
 
506
                     bar->hoveredSlot == bar->textSlot && bar->hoveredSlot)
 
507
            {
 
508
                bar->textLayer->animationTime =
 
509
                    (groupGetFadeTextTime (group->screen) * 1000) -
 
510
                    bar->textLayer->animationTime;
 
511
                bar->textLayer->state = PaintFadeIn;
 
512
            }
564
513
        }
 
514
    }
565
515
}
566
516
 
567
517
/*
575
525
 */
576
526
void
577
527
groupHandleTabBarFade (GroupSelection *group,
578
 
                                           int            msSinceLastPaint)
 
528
                       int            msSinceLastPaint)
579
529
{
580
 
        GroupTabBar *bar = group->tabBar;
581
 
 
582
 
        if ((bar->state == PaintFadeIn || bar->state == PaintFadeOut) &&
583
 
                bar->animationTime > 0)
584
 
        {
585
 
                bar->animationTime -= msSinceLastPaint;
586
 
 
587
 
                if (bar->animationTime < 0)
588
 
                        bar->animationTime = 0;
589
 
 
590
 
                /* Fade finished */
591
 
                if (bar->animationTime == 0)
592
 
                {
593
 
                        if (bar->state == PaintFadeIn)
594
 
                        {
595
 
                                bar->state = PaintOn;
596
 
                                groupCheckForVisibleTabBars (group->screen);
597
 
                        }
598
 
                        else if (bar->state == PaintFadeOut)
599
 
                        {
600
 
                                bar->state = PaintOff;
601
 
 
602
 
                                groupCheckForVisibleTabBars (group->screen);
603
 
 
604
 
                                if (bar->textLayer)
605
 
                                {
606
 
                                        /* Tab-bar is no longer painted, clean up
607
 
                                           text animation variables. */
608
 
                                        bar->textLayer->animationTime = 0;
609
 
                                        bar->textLayer->state = PaintOff;
610
 
                                        bar->textSlot = bar->hoveredSlot = NULL;
611
 
 
612
 
                                        groupRenderWindowTitle (group);
613
 
                                }
614
 
                        }
615
 
                }
616
 
        }
 
530
    GroupTabBar *bar = group->tabBar;
 
531
 
 
532
    bar->animationTime -= msSinceLastPaint;
 
533
 
 
534
    if (bar->animationTime < 0)
 
535
        bar->animationTime = 0;
 
536
 
 
537
    /* Fade finished */
 
538
    if (bar->animationTime == 0)
 
539
    {
 
540
        if (bar->state == PaintFadeIn)
 
541
        {
 
542
            bar->state = PaintOn;
 
543
        }
 
544
        else if (bar->state == PaintFadeOut)
 
545
        {
 
546
            bar->state = PaintOff;
 
547
 
 
548
            if (bar->textLayer)
 
549
            {
 
550
                /* Tab-bar is no longer painted, clean up
 
551
                   text animation variables. */
 
552
                bar->textLayer->animationTime = 0;
 
553
                bar->textLayer->state = PaintOff;
 
554
                bar->textSlot = bar->hoveredSlot = NULL;
 
555
 
 
556
                groupRenderWindowTitle (group);
 
557
            }
 
558
        }
 
559
    }
617
560
}
618
561
 
619
562
/*
626
569
 *
627
570
 */
628
571
void
629
 
groupHandleTextFade(GroupSelection *group, int msSinceLastPaint)
 
572
groupHandleTextFade (GroupSelection *group,
 
573
                     int            msSinceLastPaint)
630
574
{
631
 
        GroupTabBar     *bar = group->tabBar;
632
 
        GroupCairoLayer *textLayer = bar->textLayer;
633
 
 
634
 
        if (!textLayer)
635
 
                return;
636
 
 
637
 
        /* Fade in progress... */
638
 
        if ((textLayer->state == PaintFadeIn || textLayer->state == PaintFadeOut) &&
639
 
                textLayer->animationTime > 0)
640
 
        {
641
 
                textLayer->animationTime -= msSinceLastPaint;
642
 
 
643
 
                if (textLayer->animationTime < 0)
644
 
                        textLayer->animationTime = 0;
645
 
 
646
 
                /* Fade has finished. */
647
 
                if (textLayer->animationTime == 0)
648
 
                {
649
 
                        if (textLayer->state == PaintFadeIn)
650
 
                                textLayer->state = PaintOn;
651
 
 
652
 
                        else if (textLayer->state == PaintFadeOut)
653
 
                                textLayer->state = PaintOff;
654
 
                }
655
 
        }
656
 
 
657
 
        if (textLayer->state == PaintOff && bar->hoveredSlot)
658
 
        {
659
 
                /* Start text animation for the new hovered slot. */
660
 
                bar->textSlot = bar->hoveredSlot;
661
 
                textLayer->state = PaintFadeIn;
662
 
                textLayer->animationTime =
663
 
                        (groupGetFadeTextTime (group->screen) * 1000);
664
 
 
665
 
                groupRenderWindowTitle (group);
666
 
        }
667
 
 
668
 
        else if (textLayer->state == PaintOff && bar->textSlot)
669
 
        {
670
 
                /* Clean Up. */
671
 
                bar->textSlot = NULL;
672
 
                groupRenderWindowTitle (group);
673
 
        }
 
575
    GroupTabBar     *bar = group->tabBar;
 
576
    GroupCairoLayer *textLayer = bar->textLayer;
 
577
 
 
578
    /* Fade in progress... */
 
579
    if ((textLayer->state == PaintFadeIn || textLayer->state == PaintFadeOut) &&
 
580
        textLayer->animationTime > 0)
 
581
    {
 
582
        textLayer->animationTime -= msSinceLastPaint;
 
583
 
 
584
        if (textLayer->animationTime < 0)
 
585
            textLayer->animationTime = 0;
 
586
 
 
587
        /* Fade has finished. */
 
588
        if (textLayer->animationTime == 0)
 
589
        {
 
590
            if (textLayer->state == PaintFadeIn)
 
591
                textLayer->state = PaintOn;
 
592
 
 
593
            else if (textLayer->state == PaintFadeOut)
 
594
                textLayer->state = PaintOff;
 
595
        }
 
596
    }
 
597
 
 
598
    if (textLayer->state == PaintOff && bar->hoveredSlot)
 
599
    {
 
600
        /* Start text animation for the new hovered slot. */
 
601
        bar->textSlot = bar->hoveredSlot;
 
602
        textLayer->state = PaintFadeIn;
 
603
        textLayer->animationTime =
 
604
            (groupGetFadeTextTime (group->screen) * 1000);
 
605
 
 
606
        groupRenderWindowTitle (group);
 
607
    }
 
608
 
 
609
    else if (textLayer->state == PaintOff && bar->textSlot)
 
610
    {
 
611
        /* Clean Up. */
 
612
        bar->textSlot = NULL;
 
613
        groupRenderWindowTitle (group);
 
614
    }
674
615
}
675
616
 
676
617
/*
677
 
 * groupHanldeTabBarAnimation
 
618
 * groupHandleTabBarAnimation
678
619
 *
679
620
 * Description: Handles the different animations for the tab bar defined in
680
621
 * GroupAnimationType. Basically that means this function updates
684
625
 */
685
626
void
686
627
groupHandleTabBarAnimation (GroupSelection *group,
687
 
                                                        int            msSinceLastPaint)
 
628
                            int            msSinceLastPaint)
688
629
{
689
 
        GroupTabBar *bar = group->tabBar;
690
 
 
691
 
        if (bar->bgAnimation)
692
 
        {
693
 
                bar->bgAnimationTime -= msSinceLastPaint;
694
 
 
695
 
                if (bar->bgAnimationTime <= 0)
696
 
                {
697
 
                        bar->bgAnimationTime = 0;
698
 
                        bar->bgAnimation = 0;
699
 
 
700
 
                        groupRenderTabBarBackground (group);
701
 
                }
702
 
        }
 
630
    GroupTabBar *bar = group->tabBar;
 
631
 
 
632
    bar->bgAnimationTime -= msSinceLastPaint;
 
633
 
 
634
    if (bar->bgAnimationTime <= 0)
 
635
    {
 
636
        bar->bgAnimationTime = 0;
 
637
        bar->bgAnimation = 0;
 
638
 
 
639
        groupRenderTabBarBackground (group);
 
640
    }
703
641
}
704
642
 
705
643
/*
710
648
 */
711
649
static void
712
650
groupTabChangeActivateEvent (CompScreen *s,
713
 
                                                         Bool       activating)
 
651
                             Bool           activating)
714
652
{
715
653
    CompOption o[2];
716
654
 
723
661
    o[1].value.b = activating;
724
662
 
725
663
    (*s->display->handleCompizEvent) (s->display,
726
 
                                                                          "group", "tabChangeActivate", o, 2);
727
 
}
728
 
 
729
 
/*
730
 
 * groupHandleTabChange
731
 
 *
732
 
 * Description:
733
 
 * This function is also called from groupHandleChanges to handle
734
 
 * the tab change. It moved the new topTab on the screen as well as doing
735
 
 * the initial set for the tab change animation.
736
 
 *
737
 
 */
738
 
static void
739
 
groupHandleTabChange (GroupSelection *group)
740
 
{
741
 
        CompScreen *s;
742
 
        CompWindow *topTab;
743
 
 
744
 
        if (!group || !HAS_TOP_WIN (group) || !group->changeTab)
745
 
                return;
746
 
 
747
 
        s = group->screen;
748
 
 
749
 
        GROUP_SCREEN (s);
750
 
 
751
 
        // exit when there is a rotate or plane animation
752
 
        if (screenGrabExist (s, "rotate", "plane", "wall", 0))
753
 
                return;
754
 
 
755
 
        topTab = TOP_TAB (group);
756
 
 
757
 
        if (group->tabbingState != PaintOff)
758
 
        {
759
 
                /* if the previous top-tab window is being removed
760
 
                   from the group, move the new top-tab window onscreen. */
761
 
                if (group->ungroupState == UngroupSingle && !group->prevTopTab)
762
 
                {
763
 
                        gs->queued = TRUE;
764
 
                        groupSetWindowVisibility (topTab, TRUE);
765
 
                        moveWindow (topTab,
766
 
                                                group->oldTopTabCenterX -
767
 
                                                WIN_X (topTab) - WIN_WIDTH (topTab) / 2,
768
 
                                                group->oldTopTabCenterY -
769
 
                                                WIN_Y (topTab) - WIN_HEIGHT (topTab) / 2,
770
 
                                                TRUE, TRUE);
771
 
                        syncWindowPosition (topTab);
772
 
                        gs->queued = FALSE;
773
 
 
774
 
                        /* recalc here is needed (for y value)! */
775
 
                        groupRecalcTabBarPos (group,
776
 
                                                                  (group->tabBar->region->extents.x1 +
777
 
                                                                   group->tabBar->region->extents.x2) / 2,
778
 
                                                                  WIN_REAL_X (topTab),
779
 
                                                                  WIN_REAL_X (topTab) +
780
 
                                                                  WIN_REAL_WIDTH (topTab));
781
 
 
782
 
                        group->prevTopTab = group->topTab;
783
 
                }
784
 
 
785
 
                return;
786
 
        }
787
 
 
788
 
        gs->queued = TRUE;
789
 
        groupSetWindowVisibility (topTab, TRUE);
790
 
        moveWindow (topTab,
791
 
                                group->oldTopTabCenterX -
792
 
                                WIN_X (topTab) - WIN_WIDTH (topTab) / 2,
793
 
                                group->oldTopTabCenterY -
794
 
                                WIN_Y (topTab) - WIN_HEIGHT (topTab) / 2,
795
 
                                TRUE, TRUE);
796
 
        syncWindowPosition (topTab);
797
 
        gs->queued = FALSE;
798
 
 
799
 
        if (group->prevTopTab)
800
 
        {
801
 
                /* we use only the half time here -
802
 
                   the second half will be PaintFadeOut */
803
 
                group->changeAnimationTime = groupGetChangeAnimationTime (s) * 500;
804
 
                groupTabChangeActivateEvent (s, TRUE);
805
 
                group->changeState = PaintFadeIn;
806
 
 
807
 
                group->changeTab = FALSE;
808
 
        }
809
 
        else
810
 
        {
811
 
                /* No window to do animation with. */
812
 
                group->prevTopTab = group->topTab;
813
 
                group->changeTab = FALSE;
814
 
                activateWindow (TOP_TAB (group));
815
 
        }
816
 
 
817
 
        return;
 
664
                                      "group", "tabChangeActivate", o, 2);
818
665
}
819
666
 
820
667
/*
828
675
 * animation.
829
676
 *
830
677
 */
831
 
static void
 
678
void
832
679
groupHandleAnimation (GroupSelection *group)
833
680
{
834
 
        CompScreen *s = group->screen;
835
 
 
836
 
        if (group->tabbingState != PaintOff || !HAS_TOP_WIN (group))
837
 
                return;
838
 
 
839
 
        if (screenGrabExist (s, "rotate", "plane", "wall", 0))
840
 
                return;
841
 
 
842
 
        if (group->changeState == PaintFadeIn && group->changeAnimationTime <= 0)
843
 
        {
844
 
                /* recalc here is needed (for y value)! */
845
 
                groupRecalcTabBarPos (group,
846
 
                                                          (group->tabBar->region->extents.x1 +
847
 
                                                           group->tabBar->region->extents.x2) / 2,
848
 
                                                          WIN_REAL_X (TOP_TAB (group)),
849
 
                                                          WIN_REAL_X (TOP_TAB (group)) +
850
 
                                                          WIN_REAL_WIDTH (TOP_TAB (group)));
851
 
 
852
 
                group->changeAnimationTime += groupGetChangeAnimationTime (s) * 500;
853
 
 
854
 
                if (group->changeAnimationTime <= 0)
855
 
                        group->changeAnimationTime = 0;
856
 
 
857
 
                group->changeState = PaintFadeOut;
858
 
 
859
 
                if (HAS_TOP_WIN (group))
860
 
                        activateWindow (TOP_TAB (group));
861
 
        }
862
 
 
863
 
        if (group->changeState == PaintFadeOut && group->changeAnimationTime <= 0)
864
 
        {
865
 
                int oldChangeAnimationTime = group->changeAnimationTime;
866
 
 
867
 
                groupTabChangeActivateEvent (s, FALSE);
868
 
 
869
 
                if (group->prevTopTab)
870
 
                        groupSetWindowVisibility (PREV_TOP_TAB (group), FALSE);
871
 
 
872
 
                group->prevTopTab = group->topTab;
873
 
                group->changeState = PaintOff;
874
 
 
875
 
                if (group->nextTopTab)
876
 
                {
877
 
                        groupChangeTab (group->nextTopTab, group->nextDirection);
878
 
                        group->nextTopTab = NULL;
879
 
 
880
 
                        groupHandleTabChange (group);
881
 
 
882
 
                        if (group->changeState == PaintFadeIn)
883
 
                        {
884
 
                                /* If a new animation was started. */
885
 
                                group->changeAnimationTime += oldChangeAnimationTime;
886
 
                        }
887
 
                }
888
 
 
889
 
                if (group->changeAnimationTime <= 0)
890
 
                {
891
 
                        group->changeAnimationTime = 0;
892
 
                }
893
 
                else if (groupGetVisibilityTime (s) != 0.0f &&
894
 
                                 group->changeState == PaintOff)
895
 
                {
896
 
                        groupTabSetVisibility (group, TRUE,
897
 
                                                                   PERMANENT | SHOW_BAR_INSTANTLY_MASK);
898
 
 
899
 
                        if (group->tabBar->timeoutHandle)
900
 
                                compRemoveTimeout (group->tabBar->timeoutHandle);
901
 
 
902
 
                        group->tabBar->timeoutHandle =
903
 
                                compAddTimeout (groupGetVisibilityTime (s) * 1000,
904
 
                                                                groupTabBarTimeout, group);
905
 
                }
906
 
        }
907
 
}
908
 
 
909
 
/*
910
 
 * groupHandleTab
911
 
 *
912
 
 * Description:
913
 
 * This functions handes the offscreen moves of the tabs
914
 
 * after the animation has finished. It's called from
915
 
 * groupHandleChanges.
916
 
 *
917
 
 */
918
 
static void
919
 
groupHandleTab (GroupSelection *group)
920
 
{
921
 
        GroupTabBarSlot *slot;
922
 
 
923
 
        if (group->tabbingState == PaintOff || group->doTabbing ||
924
 
            !HAS_TOP_WIN (group) || !group->changeTab)
925
 
        {
926
 
                return;
927
 
        }
928
 
 
929
 
        for (slot = group->tabBar->slots; slot; slot = slot->next)
930
 
        {
931
 
                CompWindow *w = slot->window;
932
 
                if (!w)
933
 
                        continue;
934
 
 
935
 
                GROUP_WINDOW (w);
936
 
 
937
 
                if (slot == group->topTab ||
938
 
                        !(gw->animateState & FINISHED_ANIMATION) || gw->ungroup)
939
 
                {
940
 
                        continue;
941
 
                }
942
 
 
943
 
                groupSetWindowVisibility (w, FALSE);
944
 
        }
945
 
 
946
 
        group->changeTab = FALSE;
947
 
        group->prevTopTab = group->topTab;
948
 
}
949
 
 
950
 
/*
951
 
 * groupHandleTabbingAnimation
952
 
 *
953
 
 * Description:
954
 
 * This function handles the end of the tab
955
 
 * animation. Actually its just sets some
956
 
 * states and sync the window positions with X.
957
 
 * It's called from groupHandleChanges.
958
 
 *
959
 
 */
960
 
static void
961
 
groupHandleTabbingAnimation (GroupSelection *group)
962
 
{
963
 
        int i;
964
 
 
965
 
        if (group->tabbingState == PaintOff || group->doTabbing)
966
 
                return;
967
 
 
968
 
        GROUP_SCREEN (group->screen);
969
 
 
970
 
        /* Not animated any more. */
971
 
        group->tabbingState = PaintOff;
972
 
 
973
 
        for (i = 0; i < group->nWins; i++)
974
 
        {
975
 
                CompWindow *w = group->windows[i];
976
 
                GROUP_WINDOW (w);
977
 
 
978
 
                /* move window to target position */
979
 
                gs->queued = TRUE;
980
 
                moveWindow (w, gw->destination.x - WIN_X (w), 
981
 
                                        gw->destination.y - WIN_Y (w),
982
 
                                        TRUE, TRUE);
983
 
                gs->queued = FALSE;
984
 
                syncWindowPosition (w);
985
 
 
986
 
                gw->animateState = 0;
987
 
                gw->tx = gw->ty = gw->xVelocity = gw->yVelocity = 0.0f;
988
 
        }
989
 
}
990
 
 
991
 
/*
992
 
 * groupHandleUntab
993
 
 *
994
 
 * Description:
995
 
 * This function handles the beginning of the untab
996
 
 * animation. It deletes the tab bar and set's
997
 
 * group->prevTopTab. It's called from groupHandleChanges.
998
 
 *
999
 
 */
1000
 
static void
1001
 
groupHandleUntab (GroupSelection *group)
1002
 
{
1003
 
        if (group->tabbingState == PaintOff || !group->doTabbing)
1004
 
                return;
1005
 
 
1006
 
        if (group->topTab || !group->changeTab)
1007
 
                return;
1008
 
 
1009
 
        groupDeleteTabBar (group);
1010
 
 
1011
 
        group->changeAnimationTime = 0;
1012
 
        group->changeState = PaintOff;
1013
 
        group->nextTopTab = NULL;
1014
 
 
1015
 
        group->changeTab = FALSE;
1016
 
        group->prevTopTab = group->topTab;
1017
 
}
1018
 
 
1019
 
/*
1020
 
 * groupHandleUngroup
1021
 
 *
1022
 
 * Description:
1023
 
 * This function handles the ungroup animation for tabbed groups.
1024
 
 * It moved the windows on screen and also it calles groupDeleteGroupWindow
1025
 
 * when its a "single ungroup", which means only one window gets removed
1026
 
 * from the group. Another task of this function is to check if the group
1027
 
 * which is before the given group in the linked list needs to be deleted.
1028
 
 * This is needed to avoid problems with the linked list.
1029
 
 * It's called from groupHandleChanges.
1030
 
 *
1031
 
 */
1032
 
Bool
1033
 
groupHandleUngroup (GroupSelection *group)
1034
 
{
1035
 
        int i;
1036
 
 
1037
 
        GROUP_SCREEN (group->screen);
1038
 
 
1039
 
        if ((group->ungroupState == UngroupSingle) &&
1040
 
                group->doTabbing && group->changeTab)
1041
 
        {
1042
 
                for (i = 0; i < group->nWins; i++)
1043
 
                {
1044
 
                        CompWindow *w = group->windows[i];
1045
 
                        GROUP_WINDOW (w);
1046
 
 
1047
 
                        if (gw->ungroup)
1048
 
                        {
1049
 
                                gs->queued = TRUE;
1050
 
                                groupSetWindowVisibility (w, TRUE);
1051
 
                                moveWindow (w,
1052
 
                                                        group->oldTopTabCenterX -
1053
 
                                                        WIN_X (w) - WIN_WIDTH (w) / 2,
1054
 
                                                        group->oldTopTabCenterY -
1055
 
                                                        WIN_Y (w) - WIN_HEIGHT (w) / 2,
1056
 
                                                        TRUE, TRUE);
1057
 
                                syncWindowPosition (w);
1058
 
                                gs->queued = FALSE;
1059
 
                        }
1060
 
                }
1061
 
 
1062
 
                group->changeTab = FALSE;
1063
 
        }
1064
 
 
1065
 
        if ((group->ungroupState == UngroupSingle) && !group->doTabbing)
1066
 
        {
1067
 
                Bool morePending;
1068
 
 
1069
 
                do
1070
 
                {
1071
 
                        morePending = FALSE;
1072
 
 
1073
 
                        for (i = 0;i < group->nWins; i++)
1074
 
                        {
1075
 
                                CompWindow *w = group->windows[i];
1076
 
                                GROUP_WINDOW (w);
1077
 
 
1078
 
                                if (gw->ungroup)
1079
 
                                {
1080
 
                                        groupDeleteGroupWindow (w, TRUE);
1081
 
                                        gw->ungroup = FALSE;
1082
 
                                        morePending = TRUE;
1083
 
                                }
1084
 
                        }
1085
 
                }
1086
 
                while (morePending);
1087
 
 
1088
 
                group->ungroupState = UngroupNone;
1089
 
        }
1090
 
 
1091
 
        if (group->prev)
1092
 
        {
1093
 
                if ((group->prev->ungroupState == UngroupAll) &&
1094
 
                        !group->prev->doTabbing)
1095
 
                {
1096
 
                        groupDeleteGroup (group->prev);
1097
 
                }
1098
 
        }
1099
 
        if (!group->next)
1100
 
        {
1101
 
                if ((group->ungroupState == UngroupAll) && !group->doTabbing)
1102
 
                {
1103
 
                        groupDeleteGroup (group);
1104
 
                        return FALSE;
1105
 
                }
1106
 
        }
1107
 
 
1108
 
        return TRUE;
1109
 
}
1110
 
 
1111
 
/*
1112
 
 * groupHandleChanges
1113
 
 *
1114
 
 * Description:
1115
 
 * This function is called from groupPreparePaintScreen to
1116
 
 * go through all groups and apply the other "handle functions"
1117
 
 * on them.
1118
 
 *
1119
 
 */
1120
 
void
1121
 
groupHandleChanges (CompScreen *s)
1122
 
{
1123
 
        GroupSelection *group;
1124
 
 
1125
 
        GROUP_SCREEN (s);
1126
 
 
1127
 
        for (group = gs->groups; group; group = group ? group->next : NULL)
1128
 
        {
1129
 
                groupHandleUntab (group);
1130
 
                groupHandleTab (group);
1131
 
                groupHandleTabbingAnimation (group);
1132
 
                groupHandleTabChange (group);
1133
 
                groupHandleAnimation (group);
1134
 
 
1135
 
                if (!groupHandleUngroup (group))
1136
 
                        group = NULL;
1137
 
        }
 
681
    CompScreen *s = group->screen;
 
682
 
 
683
    if (group->changeState == TabChangeOldOut)
 
684
    {
 
685
        CompWindow *top = TOP_TAB (group);
 
686
 
 
687
        /* recalc here is needed (for y value)! */
 
688
        groupRecalcTabBarPos (group,
 
689
                              (group->tabBar->region->extents.x1 +
 
690
                               group->tabBar->region->extents.x2) / 2,
 
691
                              WIN_REAL_X (top),
 
692
                              WIN_REAL_X (top) + WIN_REAL_WIDTH (top));
 
693
 
 
694
        group->changeAnimationTime += groupGetChangeAnimationTime (s) * 500;
 
695
 
 
696
        if (group->changeAnimationTime <= 0)
 
697
            group->changeAnimationTime = 0;
 
698
 
 
699
        group->changeState = TabChangeNewIn;
 
700
 
 
701
        activateWindow (top);
 
702
    }
 
703
 
 
704
    if (group->changeState == TabChangeNewIn &&
 
705
        group->changeAnimationTime <= 0)
 
706
    {
 
707
        int oldChangeAnimationTime = group->changeAnimationTime;
 
708
 
 
709
        groupTabChangeActivateEvent (s, FALSE);
 
710
 
 
711
        if (group->prevTopTab)
 
712
            groupSetWindowVisibility (PREV_TOP_TAB (group), FALSE);
 
713
 
 
714
        group->prevTopTab = group->topTab;
 
715
        group->changeState = NoTabChange;
 
716
 
 
717
        if (group->nextTopTab)
 
718
        {
 
719
            GroupTabBarSlot *next = group->nextTopTab;
 
720
            group->nextTopTab = NULL;
 
721
 
 
722
            groupChangeTab (next, group->nextDirection);
 
723
 
 
724
            if (group->changeState == TabChangeOldOut)
 
725
            {
 
726
                /* If a new animation was started. */
 
727
                group->changeAnimationTime += oldChangeAnimationTime;
 
728
            }
 
729
        }
 
730
 
 
731
        if (group->changeAnimationTime <= 0)
 
732
        {
 
733
            group->changeAnimationTime = 0;
 
734
        }
 
735
        else if (groupGetVisibilityTime (s) != 0.0f &&
 
736
                 group->changeState == NoTabChange)
 
737
        {
 
738
            groupTabSetVisibility (group, TRUE,
 
739
                                   PERMANENT | SHOW_BAR_INSTANTLY_MASK);
 
740
 
 
741
            if (group->tabBar->timeoutHandle)
 
742
                compRemoveTimeout (group->tabBar->timeoutHandle);
 
743
 
 
744
            group->tabBar->timeoutHandle =
 
745
                compAddTimeout (groupGetVisibilityTime (s) * 1000,
 
746
                                groupTabBarTimeout, group);
 
747
        }
 
748
    }
1138
749
}
1139
750
 
1140
751
/* adjust velocity for each animation step (adapted from the scale plugin) */
1141
752
static int
1142
753
adjustTabVelocity (CompWindow *w)
1143
754
{
1144
 
        float dx, dy, adjust, amount;
1145
 
        float x1, y1;
1146
 
 
 
755
    float dx, dy, adjust, amount;
 
756
    float x1, y1;
 
757
 
 
758
    GROUP_WINDOW (w);
 
759
 
 
760
    x1 = gw->destination.x;
 
761
    y1 = gw->destination.y;
 
762
 
 
763
    dx = x1 - (gw->orgPos.x + gw->tx);
 
764
    adjust = dx * 0.15f;
 
765
    amount = fabs (dx) * 1.5f;
 
766
    if (amount < 0.5f)
 
767
        amount = 0.5f;
 
768
    else if (amount > 5.0f)
 
769
        amount = 5.0f;
 
770
 
 
771
    gw->xVelocity = (amount * gw->xVelocity + adjust) / (amount + 1.0f);
 
772
 
 
773
    dy = y1 - (gw->orgPos.y + gw->ty);
 
774
    adjust = dy * 0.15f;
 
775
    amount = fabs (dy) * 1.5f;
 
776
    if (amount < 0.5f)
 
777
        amount = 0.5f;
 
778
    else if (amount > 5.0f)
 
779
        amount = 5.0f;
 
780
 
 
781
    gw->yVelocity = (amount * gw->yVelocity + adjust) / (amount + 1.0f);
 
782
 
 
783
    if (fabs (dx) < 0.1f && fabs (gw->xVelocity) < 0.2f &&
 
784
        fabs (dy) < 0.1f && fabs (gw->yVelocity) < 0.2f)
 
785
    {
 
786
        gw->xVelocity = gw->yVelocity = 0.0f;
 
787
        gw->tx = x1 - w->serverX;
 
788
        gw->ty = y1 - w->serverY;
 
789
 
 
790
        return 0;
 
791
    }
 
792
    return 1;
 
793
}
 
794
 
 
795
static void
 
796
groupFinishTabbing (GroupSelection *group)
 
797
{
 
798
    CompScreen *s = group->screen;
 
799
    int        i;
 
800
 
 
801
    GROUP_SCREEN (s);
 
802
 
 
803
    group->tabbingState = NoTabbing;
 
804
    groupTabChangeActivateEvent (s, FALSE);
 
805
 
 
806
    if (group->tabBar)
 
807
    {
 
808
        /* tabbing case - hide all non-toptab windows */
 
809
        GroupTabBarSlot *slot;
 
810
 
 
811
        for (slot = group->tabBar->slots; slot; slot = slot->next)
 
812
        {
 
813
            CompWindow *w = slot->window;
 
814
            if (!w)
 
815
                continue;
 
816
 
 
817
            GROUP_WINDOW (w);
 
818
 
 
819
            if (slot == group->topTab || (gw->animateState & IS_UNGROUPING))
 
820
                continue;
 
821
 
 
822
            groupSetWindowVisibility (w, FALSE);
 
823
        }
 
824
        group->prevTopTab = group->topTab;
 
825
    }
 
826
 
 
827
    for (i = 0; i < group->nWins; i++)
 
828
    {
 
829
        CompWindow *w = group->windows[i];
1147
830
        GROUP_WINDOW (w);
1148
831
 
1149
 
        if (!(gw->animateState & IS_ANIMATED))
1150
 
                return 0;
1151
 
 
1152
 
        x1 = gw->destination.x;
1153
 
        y1 = gw->destination.y;
1154
 
 
1155
 
        dx = x1 - (gw->orgPos.x + gw->tx);
1156
 
        adjust = dx * 0.15f;
1157
 
        amount = fabs (dx) * 1.5f;
1158
 
        if (amount < 0.5f)
1159
 
                amount = 0.5f;
1160
 
        else if (amount > 5.0f)
1161
 
                amount = 5.0f;
1162
 
 
1163
 
        gw->xVelocity = (amount * gw->xVelocity + adjust) / (amount + 1.0f);
1164
 
 
1165
 
        dy = y1 - (gw->orgPos.y + gw->ty);
1166
 
        adjust = dy * 0.15f;
1167
 
        amount = fabs (dy) * 1.5f;
1168
 
        if (amount < 0.5f)
1169
 
                amount = 0.5f;
1170
 
        else if (amount > 5.0f)
1171
 
                amount = 5.0f;
1172
 
 
1173
 
        gw->yVelocity = (amount * gw->yVelocity + adjust) / (amount + 1.0f);
1174
 
 
1175
 
        if (fabs (dx) < 0.1f && fabs (gw->xVelocity) < 0.2f &&
1176
 
                fabs (dy) < 0.1f && fabs (gw->yVelocity) < 0.2f)
 
832
        /* move window to target position */
 
833
        gs->queued = TRUE;
 
834
        moveWindow (w, gw->destination.x - WIN_X (w),
 
835
                    gw->destination.y - WIN_Y (w), TRUE, TRUE);
 
836
        gs->queued = FALSE;
 
837
        syncWindowPosition (w);
 
838
 
 
839
        if (group->ungroupState == UngroupSingle &&
 
840
            (gw->animateState & IS_UNGROUPING))
1177
841
        {
1178
 
                gw->xVelocity = gw->yVelocity = 0.0f;
1179
 
                gw->tx = x1 - w->serverX;
1180
 
                gw->ty = y1 - w->serverY;
1181
 
 
1182
 
                return 0;
 
842
            groupRemoveWindowFromGroup (w);
1183
843
        }
1184
 
        return 1;
 
844
 
 
845
        gw->animateState = 0;
 
846
        gw->tx = gw->ty = gw->xVelocity = gw->yVelocity = 0.0f;
 
847
    }
 
848
 
 
849
    if (group->ungroupState == UngroupAll)
 
850
        groupDeleteGroup (group);
 
851
    group->ungroupState = UngroupNone;
1185
852
}
1186
853
 
1187
854
/*
1196
863
 *
1197
864
 */
1198
865
void
1199
 
groupDrawTabAnimation (CompScreen *s,
1200
 
                                           int        msSinceLastPaint)
 
866
groupDrawTabAnimation (GroupSelection *group,
 
867
                       int            msSinceLastPaint)
1201
868
{
1202
 
        int            i;
1203
 
        GroupSelection *group;
1204
 
 
1205
 
        GROUP_SCREEN(s);
1206
 
 
1207
 
        for (group = gs->groups; group; group = group->next)
1208
 
        {
1209
 
                int   steps;
1210
 
                float amount, chunk;
1211
 
 
1212
 
                if (group->tabbingState == PaintOff)
1213
 
                        continue;
1214
 
 
1215
 
                amount = msSinceLastPaint * 0.05f * groupGetTabbingSpeed (s);
1216
 
                steps = amount / (0.5f * groupGetTabbingTimestep (s));
1217
 
                if (!steps)
1218
 
                        steps = 1;
1219
 
                chunk = amount / (float)steps;
1220
 
 
1221
 
                while (steps--)
1222
 
                {
1223
 
                        group->doTabbing = FALSE;
1224
 
 
1225
 
                        for (i = 0; i < group->nWins; i++)
1226
 
                        {
1227
 
                                CompWindow *cw = group->windows[i];
1228
 
                                if (!cw)
1229
 
                                        continue;
1230
 
 
1231
 
                                GROUP_WINDOW (cw);
1232
 
 
1233
 
                                if (!(gw->animateState & IS_ANIMATED))
1234
 
                                        continue;
1235
 
 
1236
 
                                if (!adjustTabVelocity (cw))
1237
 
                                {
1238
 
                                        gw->animateState |= FINISHED_ANIMATION;
1239
 
                                        gw->animateState &= ~(IS_ANIMATED);
1240
 
                                }
1241
 
 
1242
 
                                gw->tx += gw->xVelocity * chunk;
1243
 
                                gw->ty += gw->yVelocity * chunk;
1244
 
 
1245
 
                                group->doTabbing |= (gw->animateState & IS_ANIMATED);
1246
 
                        }
1247
 
                        if (!group->doTabbing)
1248
 
                                break;
1249
 
                }
1250
 
        }
 
869
    int        steps, i;
 
870
    float      amount, chunk;
 
871
    Bool       doTabbing;
 
872
    CompScreen *s = group->screen;
 
873
 
 
874
    amount = msSinceLastPaint * 0.05f * groupGetTabbingSpeed (s);
 
875
    steps = amount / (0.5f * groupGetTabbingTimestep (s));
 
876
    if (!steps)
 
877
        steps = 1;
 
878
    chunk = amount / (float)steps;
 
879
 
 
880
    while (steps--)
 
881
    {
 
882
        doTabbing = FALSE;
 
883
 
 
884
        for (i = 0; i < group->nWins; i++)
 
885
        {
 
886
            CompWindow *cw = group->windows[i];
 
887
            if (!cw)
 
888
                continue;
 
889
 
 
890
            GROUP_WINDOW (cw);
 
891
 
 
892
            if (!(gw->animateState & IS_ANIMATED))
 
893
                continue;
 
894
 
 
895
            if (!adjustTabVelocity (cw))
 
896
            {
 
897
                gw->animateState |= FINISHED_ANIMATION;
 
898
                gw->animateState &= ~IS_ANIMATED;
 
899
            }
 
900
 
 
901
            gw->tx += gw->xVelocity * chunk;
 
902
            gw->ty += gw->yVelocity * chunk;
 
903
 
 
904
            doTabbing |= (gw->animateState & IS_ANIMATED);
 
905
        }
 
906
 
 
907
        if (!doTabbing)
 
908
        {
 
909
            /* tabbing animation finished */
 
910
            groupFinishTabbing (group);
 
911
            break;
 
912
        }
 
913
    }
1251
914
}
1252
915
 
1253
916
/*
1265
928
 */
1266
929
void
1267
930
groupUpdateTabBars (CompScreen *s,
1268
 
                                        Window     enteredWin)
 
931
                    Window     enteredWin)
1269
932
{
1270
 
        CompWindow     *w;
1271
 
        GroupSelection *hoveredGroup = NULL;
1272
 
 
1273
 
        GROUP_SCREEN (s);
1274
 
 
1275
 
        /* first check if the entered window is a frame */
1276
 
        for (w = s->windows; w; w = w->next)
1277
 
        {
1278
 
                if (w->frame == enteredWin)
1279
 
                        break;
1280
 
        }
1281
 
 
1282
 
        if (w)
1283
 
        {
1284
 
                /* is the window the entered frame belongs to inside
1285
 
                   a tabbed group? if no, it's not interesting for us */
1286
 
                GROUP_WINDOW (w);
1287
 
                if (gw->group && gw->group->tabBar)
1288
 
                {
1289
 
                        int mouseX, mouseY;
1290
 
                        /* it is grouped and tabbed, so now we have to
1291
 
                           check if we hovered the title bar or the frame */
1292
 
                        if (groupGetCurrentMousePosition (s, &mouseX, &mouseY))
1293
 
                        {
1294
 
                                XRectangle rect;
1295
 
                                Region     reg = XCreateRegion();
1296
 
                                if (!reg)
1297
 
                                        return;
1298
 
 
1299
 
                                rect.x = WIN_X (w) - w->input.left;
1300
 
                                rect.y = WIN_Y (w) - w->input.top;
1301
 
                                rect.width = WIN_WIDTH (w) + w->input.right;
1302
 
                                rect.height = WIN_Y (w) - rect.y;
1303
 
                                XUnionRectWithRegion (&rect, reg, reg);
1304
 
 
1305
 
                                if (XPointInRegion (reg, mouseX, mouseY))
1306
 
                                        hoveredGroup = gw->group;
1307
 
 
1308
 
                                XDestroyRegion (reg);
1309
 
                        }
1310
 
                }
1311
 
        }
1312
 
 
1313
 
        /* if we didn't hover a title bar, check if we hovered
1314
 
           a tab bar (means: input prevention window) */
1315
 
        if (!hoveredGroup)
1316
 
        {
1317
 
                GroupSelection *group;
1318
 
 
1319
 
                for (group = gs->groups; group; group = group->next)
1320
 
                {
1321
 
                        if (group->inputPrevention == enteredWin)
1322
 
                        {
1323
 
                                /* only accept it if the IPW is mapped */
1324
 
                                if (group->ipwMapped)
1325
 
                                {
1326
 
                                        hoveredGroup = group;
1327
 
                                        break;
1328
 
                                }
1329
 
                        }
1330
 
                }
1331
 
        }
1332
 
 
1333
 
        /* if we found a hovered a tab bar different than the last one
1334
 
           (or left a tab bar), hide the old one */
1335
 
        if (gs->lastHoveredGroup && (hoveredGroup != gs->lastHoveredGroup))
1336
 
                groupTabSetVisibility (gs->lastHoveredGroup, FALSE, 0);
1337
 
 
1338
 
        /* if we entered a tab bar (or title bar), show the tab bar */
1339
 
        if (hoveredGroup && HAS_TOP_WIN(hoveredGroup) &&
1340
 
                !TOP_TAB(hoveredGroup)->grabbed)
1341
 
        {
1342
 
                GroupTabBar *bar = hoveredGroup->tabBar;
1343
 
 
1344
 
                if (bar && ((bar->state == PaintOff) || (bar->state == PaintFadeOut)))
1345
 
                {
1346
 
                        int showDelayTime = groupGetTabbarShowDelay (s) * 1000;
1347
 
 
1348
 
                        /* Show the tab-bar after a delay,
1349
 
                           only if the tab-bar wasn't fading out. */
1350
 
                        if (showDelayTime > 0 && (bar->state == PaintOff))
1351
 
                        {
1352
 
                                if (gs->showDelayTimeoutHandle)
1353
 
                                        compRemoveTimeout (gs->showDelayTimeoutHandle);
1354
 
                                gs->showDelayTimeoutHandle =
1355
 
                                        compAddTimeout (showDelayTime,
1356
 
                                                                        groupShowDelayTimeout, hoveredGroup);
1357
 
                        }
1358
 
                        else
1359
 
                                groupShowDelayTimeout (hoveredGroup);
1360
 
                }
1361
 
        }
1362
 
 
1363
 
        gs->lastHoveredGroup = hoveredGroup;
 
933
    CompWindow     *w;
 
934
    GroupSelection *hoveredGroup = NULL;
 
935
 
 
936
    GROUP_SCREEN (s);
 
937
 
 
938
    /* first check if the entered window is a frame */
 
939
    for (w = s->windows; w; w = w->next)
 
940
    {
 
941
        if (w->frame == enteredWin)
 
942
            break;
 
943
    }
 
944
 
 
945
    if (w)
 
946
    {
 
947
        /* is the window the entered frame belongs to inside
 
948
           a tabbed group? if no, it's not interesting for us */
 
949
        GROUP_WINDOW (w);
 
950
 
 
951
        if (gw->group && gw->group->tabBar)
 
952
        {
 
953
            int mouseX, mouseY;
 
954
            /* it is grouped and tabbed, so now we have to
 
955
               check if we hovered the title bar or the frame */
 
956
            if (groupGetCurrentMousePosition (s, &mouseX, &mouseY))
 
957
            {
 
958
                XRectangle rect;
 
959
                Region     reg = XCreateRegion();
 
960
                if (!reg)
 
961
                    return;
 
962
 
 
963
                rect.x      = WIN_X (w) - w->input.left;
 
964
                rect.y      = WIN_Y (w) - w->input.top;
 
965
                rect.width  = WIN_WIDTH (w) + w->input.right;
 
966
                rect.height = WIN_Y (w) - rect.y;
 
967
                XUnionRectWithRegion (&rect, reg, reg);
 
968
 
 
969
                if (XPointInRegion (reg, mouseX, mouseY))
 
970
                    hoveredGroup = gw->group;
 
971
 
 
972
                XDestroyRegion (reg);
 
973
            }
 
974
        }
 
975
    }
 
976
 
 
977
    /* if we didn't hover a title bar, check if we hovered
 
978
       a tab bar (means: input prevention window) */
 
979
    if (!hoveredGroup)
 
980
    {
 
981
        GroupSelection *group;
 
982
 
 
983
        for (group = gs->groups; group; group = group->next)
 
984
        {
 
985
            if (group->inputPrevention == enteredWin)
 
986
            {
 
987
                /* only accept it if the IPW is mapped */
 
988
                if (group->ipwMapped)
 
989
                {
 
990
                    hoveredGroup = group;
 
991
                    break;
 
992
                }
 
993
            }
 
994
        }
 
995
    }
 
996
 
 
997
    /* if we found a hovered tab bar different than the last one
 
998
       (or left a tab bar), hide the old one */
 
999
    if (gs->lastHoveredGroup && (hoveredGroup != gs->lastHoveredGroup))
 
1000
        groupTabSetVisibility (gs->lastHoveredGroup, FALSE, 0);
 
1001
 
 
1002
    /* if we entered a tab bar (or title bar), show the tab bar */
 
1003
    if (hoveredGroup && HAS_TOP_WIN (hoveredGroup) &&
 
1004
        !TOP_TAB (hoveredGroup)->grabbed)
 
1005
    {
 
1006
        GroupTabBar *bar = hoveredGroup->tabBar;
 
1007
 
 
1008
        if (bar && ((bar->state == PaintOff) || (bar->state == PaintFadeOut)))
 
1009
        {
 
1010
            int showDelayTime = groupGetTabbarShowDelay (s) * 1000;
 
1011
 
 
1012
            /* Show the tab-bar after a delay,
 
1013
               only if the tab-bar wasn't fading out. */
 
1014
            if (showDelayTime > 0 && (bar->state == PaintOff))
 
1015
            {
 
1016
                if (gs->showDelayTimeoutHandle)
 
1017
                    compRemoveTimeout (gs->showDelayTimeoutHandle);
 
1018
                gs->showDelayTimeoutHandle =
 
1019
                    compAddTimeout (showDelayTime,
 
1020
                                    groupShowDelayTimeout, hoveredGroup);
 
1021
            }
 
1022
            else
 
1023
                groupShowDelayTimeout (hoveredGroup);
 
1024
        }
 
1025
    }
 
1026
 
 
1027
    gs->lastHoveredGroup = hoveredGroup;
1364
1028
}
1365
1029
 
1366
1030
/*
1370
1034
static Region
1371
1035
groupGetConstrainRegion (CompScreen *s)
1372
1036
{
1373
 
        CompWindow *w;
1374
 
        Region     region;
1375
 
        REGION     r;
1376
 
        int        i;
1377
 
 
1378
 
        region = XCreateRegion ();
1379
 
        if (!region)
1380
 
                return NULL;
1381
 
 
1382
 
        for (i = 0;i < s->nOutputDev; i++)
1383
 
                XUnionRegion (&s->outputDev[i].region, region, region);
1384
 
 
1385
 
        r.rects    = &r.extents;
1386
 
        r.numRects = r.size = 1;
1387
 
 
1388
 
        for (w = s->windows; w; w = w->next)
 
1037
    CompWindow *w;
 
1038
    Region     region;
 
1039
    REGION     r;
 
1040
    int        i;
 
1041
 
 
1042
    region = XCreateRegion ();
 
1043
    if (!region)
 
1044
        return NULL;
 
1045
 
 
1046
    for (i = 0;i < s->nOutputDev; i++)
 
1047
        XUnionRegion (&s->outputDev[i].region, region, region);
 
1048
 
 
1049
    r.rects    = &r.extents;
 
1050
    r.numRects = r.size = 1;
 
1051
 
 
1052
    for (w = s->windows; w; w = w->next)
 
1053
    {
 
1054
        if (!w->mapNum)
 
1055
            continue;
 
1056
 
 
1057
        if (w->struts)
1389
1058
        {
1390
 
                if (!w->mapNum)
1391
 
                         continue;
1392
 
 
1393
 
                if (w->struts)
1394
 
                {
1395
 
                        r.extents.x1 = w->struts->top.x;
1396
 
                        r.extents.y1 = w->struts->top.y;
1397
 
                        r.extents.x2 = r.extents.x1 + w->struts->top.width;
1398
 
                        r.extents.y2 = r.extents.y1 + w->struts->top.height;
1399
 
 
1400
 
                        XSubtractRegion (region, &r, region);
1401
 
 
1402
 
                        r.extents.x1 = w->struts->bottom.x;
1403
 
                        r.extents.y1 = w->struts->bottom.y;
1404
 
                        r.extents.x2 = r.extents.x1 + w->struts->bottom.width;
1405
 
                        r.extents.y2 = r.extents.y1 + w->struts->bottom.height;
1406
 
 
1407
 
                        XSubtractRegion (region, &r, region);
1408
 
 
1409
 
                        r.extents.x1 = w->struts->left.x;
1410
 
                        r.extents.y1 = w->struts->left.y;
1411
 
                        r.extents.x2 = r.extents.x1 + w->struts->left.width;
1412
 
                        r.extents.y2 = r.extents.y1 + w->struts->left.height;
1413
 
 
1414
 
                        XSubtractRegion (region, &r, region);
1415
 
 
1416
 
                        r.extents.x1 = w->struts->right.x;
1417
 
                        r.extents.y1 = w->struts->right.y;
1418
 
                        r.extents.x2 = r.extents.x1 + w->struts->right.width;
1419
 
                        r.extents.y2 = r.extents.y1 + w->struts->right.height;
1420
 
 
1421
 
                        XSubtractRegion (region, &r, region);
1422
 
                }
 
1059
            r.extents.x1 = w->struts->top.x;
 
1060
            r.extents.y1 = w->struts->top.y;
 
1061
            r.extents.x2 = r.extents.x1 + w->struts->top.width;
 
1062
            r.extents.y2 = r.extents.y1 + w->struts->top.height;
 
1063
 
 
1064
            XSubtractRegion (region, &r, region);
 
1065
 
 
1066
            r.extents.x1 = w->struts->bottom.x;
 
1067
            r.extents.y1 = w->struts->bottom.y;
 
1068
            r.extents.x2 = r.extents.x1 + w->struts->bottom.width;
 
1069
            r.extents.y2 = r.extents.y1 + w->struts->bottom.height;
 
1070
 
 
1071
            XSubtractRegion (region, &r, region);
 
1072
 
 
1073
            r.extents.x1 = w->struts->left.x;
 
1074
            r.extents.y1 = w->struts->left.y;
 
1075
            r.extents.x2 = r.extents.x1 + w->struts->left.width;
 
1076
            r.extents.y2 = r.extents.y1 + w->struts->left.height;
 
1077
 
 
1078
            XSubtractRegion (region, &r, region);
 
1079
 
 
1080
            r.extents.x1 = w->struts->right.x;
 
1081
            r.extents.y1 = w->struts->right.y;
 
1082
            r.extents.x2 = r.extents.x1 + w->struts->right.width;
 
1083
            r.extents.y2 = r.extents.y1 + w->struts->right.height;
 
1084
 
 
1085
            XSubtractRegion (region, &r, region);
1423
1086
        }
 
1087
    }
1424
1088
 
1425
 
        return region;
 
1089
    return region;
1426
1090
}
1427
1091
 
1428
1092
/*
1431
1095
 */
1432
1096
static Bool
1433
1097
groupConstrainMovement (CompWindow *w,
1434
 
                                                Region     constrainRegion,
1435
 
                                                int        dx,
1436
 
                                                int        dy,
1437
 
                                                int        *new_dx,
1438
 
                                                int        *new_dy)
 
1098
                        Region     constrainRegion,
 
1099
                        int        dx,
 
1100
                        int        dy,
 
1101
                        int        *new_dx,
 
1102
                        int        *new_dy)
1439
1103
{
1440
 
        int status, xStatus;
1441
 
        int origDx = dx, origDy = dy;
1442
 
        int x, y, width, height;
1443
 
 
1444
 
        GROUP_WINDOW (w);
1445
 
 
1446
 
        if (!gw->group)
1447
 
                return FALSE;
1448
 
 
1449
 
        if (!dx && !dy)
1450
 
                return FALSE;
 
1104
    int status, xStatus;
 
1105
    int origDx = dx, origDy = dy;
 
1106
    int x, y, width, height;
 
1107
 
 
1108
    GROUP_WINDOW (w);
 
1109
 
 
1110
    if (!gw->group)
 
1111
        return FALSE;
 
1112
 
 
1113
    if (!dx && !dy)
 
1114
        return FALSE;
 
1115
 
 
1116
    x = gw->orgPos.x - w->input.left + dx;
 
1117
    y = gw->orgPos.y - w->input.top + dy;
 
1118
    width = WIN_REAL_WIDTH (w);
 
1119
    height = WIN_REAL_HEIGHT (w);
 
1120
 
 
1121
    status = XRectInRegion (constrainRegion, x, y, width, height);
 
1122
 
 
1123
    xStatus = status;
 
1124
    while (dx && (xStatus != RectangleIn))
 
1125
    {
 
1126
        xStatus = XRectInRegion (constrainRegion, x, y - dy, width, height);
 
1127
 
 
1128
        if (xStatus != RectangleIn)
 
1129
            dx += (dx < 0) ? 1 : -1;
1451
1130
 
1452
1131
        x = gw->orgPos.x - w->input.left + dx;
 
1132
    }
 
1133
 
 
1134
    while (dy && (status != RectangleIn))
 
1135
    {
 
1136
        status = XRectInRegion(constrainRegion, x, y, width, height);
 
1137
 
 
1138
        if (status != RectangleIn)
 
1139
            dy += (dy < 0) ? 1 : -1;
 
1140
 
1453
1141
        y = gw->orgPos.y - w->input.top + dy;
1454
 
        width = WIN_REAL_WIDTH (w);
1455
 
        height = WIN_REAL_HEIGHT (w);
1456
 
 
1457
 
        status = XRectInRegion (constrainRegion, x, y, width, height);
1458
 
 
1459
 
        xStatus = status;
1460
 
        while (dx && (xStatus != RectangleIn))
1461
 
        {
1462
 
                xStatus = XRectInRegion (constrainRegion, x, y - dy, width, height);
1463
 
 
1464
 
                if (xStatus != RectangleIn)
1465
 
                        dx += (dx < 0) ? 1 : -1;
1466
 
 
1467
 
                x = gw->orgPos.x - w->input.left + dx;
1468
 
        }
1469
 
 
1470
 
        while (dy && (status != RectangleIn))
1471
 
        {
1472
 
                status = XRectInRegion(constrainRegion, x, y, width, height);
1473
 
 
1474
 
                if (status != RectangleIn)
1475
 
                        dy += (dy < 0) ? 1 : -1;
1476
 
 
1477
 
                y = gw->orgPos.y - w->input.top + dy;
1478
 
        }
1479
 
 
1480
 
        if (new_dx)
1481
 
                *new_dx = dx;
1482
 
 
1483
 
        if (new_dy)
1484
 
                *new_dy = dy;
1485
 
 
1486
 
        return ((dx != origDx) || (dy != origDy));
 
1142
    }
 
1143
 
 
1144
    if (new_dx)
 
1145
        *new_dx = dx;
 
1146
 
 
1147
    if (new_dy)
 
1148
        *new_dy = dy;
 
1149
 
 
1150
    return ((dx != origDx) || (dy != origDy));
1487
1151
}
1488
1152
 
1489
1153
/*
1490
 
 * groupApplyConstrainingToWindows
 
1154
 * groupApplyConstraining
1491
1155
 *
1492
1156
 */
1493
1157
static void
1494
 
groupApplyConstrainingToWindows (GroupSelection *group,
1495
 
                                                                 Region         constrainRegion,
1496
 
                                                                 Window         constrainedWindow,
1497
 
                                                                 int            dx,
1498
 
                                                                 int            dy)
1499
 
{
1500
 
        int        i;
1501
 
        CompWindow *w;
1502
 
 
1503
 
        if (!dx && !dy)
1504
 
                return;
1505
 
 
 
1158
groupApplyConstraining (GroupSelection *group,
 
1159
                        Region         constrainRegion,
 
1160
                        Window         constrainedWindow,
 
1161
                        int            dx,
 
1162
                        int            dy)
 
1163
{
 
1164
    int        i;
 
1165
    CompWindow *w;
 
1166
 
 
1167
    if (!dx && !dy)
 
1168
        return;
 
1169
 
 
1170
    for (i = 0; i < group->nWins; i++)
 
1171
    {
 
1172
        w = group->windows[i];
 
1173
        GROUP_WINDOW (w);
 
1174
 
 
1175
        /* ignore certain windows: we don't want to apply the constraining
 
1176
           results on the constrained window itself, nor do we want to
 
1177
           change the target position of unamimated windows and of
 
1178
           windows which already are constrained */
 
1179
        if (w->id == constrainedWindow)
 
1180
            continue;
 
1181
 
 
1182
        if (!(gw->animateState & IS_ANIMATED))
 
1183
            continue;
 
1184
 
 
1185
        if (gw->animateState & DONT_CONSTRAIN)
 
1186
            continue;
 
1187
 
 
1188
        if (!(gw->animateState & CONSTRAINED_X))
 
1189
        {
 
1190
            gw->animateState |= IS_ANIMATED;
 
1191
 
 
1192
            /* applying the constraining result of another window
 
1193
               might move the window offscreen, too, so check
 
1194
               if this is not the case */
 
1195
            if (groupConstrainMovement (w, constrainRegion, dx, 0, &dx, NULL))
 
1196
                gw->animateState |= CONSTRAINED_X;
 
1197
 
 
1198
            gw->destination.x += dx;
 
1199
        }
 
1200
 
 
1201
        if (!(gw->animateState & CONSTRAINED_Y))
 
1202
        {
 
1203
            gw->animateState |= IS_ANIMATED;
 
1204
 
 
1205
            /* analog to X case */
 
1206
            if (groupConstrainMovement (w, constrainRegion, 0, dy, NULL, &dy))
 
1207
                gw->animateState |= CONSTRAINED_Y;
 
1208
 
 
1209
            gw->destination.y += dy;
 
1210
        }
 
1211
    }
 
1212
}
 
1213
 
 
1214
/*
 
1215
 * groupStartTabbingAnimation
 
1216
 *
 
1217
 */
 
1218
void
 
1219
groupStartTabbingAnimation (GroupSelection *group,
 
1220
                            Bool           tab)
 
1221
{
 
1222
    CompScreen *s;
 
1223
    int        i;
 
1224
    int        dx, dy;
 
1225
    int        constrainStatus;
 
1226
 
 
1227
    if (!group || (group->tabbingState != NoTabbing))
 
1228
        return;
 
1229
 
 
1230
    s = group->screen;
 
1231
    group->tabbingState = (tab) ? Tabbing : Untabbing;
 
1232
    groupTabChangeActivateEvent (s, TRUE);
 
1233
 
 
1234
    if (!tab)
 
1235
    {
 
1236
        /* we need to set up the X/Y constraining on untabbing */
 
1237
        Region constrainRegion = groupGetConstrainRegion (s);
 
1238
        Bool   constrainedWindows = TRUE;
 
1239
 
 
1240
        if (!constrainRegion)
 
1241
            return;
 
1242
 
 
1243
        /* reset all flags */
1506
1244
        for (i = 0; i < group->nWins; i++)
1507
1245
        {
1508
 
                w = group->windows[i];
 
1246
            GROUP_WINDOW (group->windows[i]);
 
1247
            gw->animateState &= ~(CONSTRAINED_X | CONSTRAINED_Y |
 
1248
                                  DONT_CONSTRAIN);
 
1249
        }
 
1250
 
 
1251
        /* as we apply the constraining in a flat loop,
 
1252
           we may need to run multiple times through this
 
1253
           loop until all constraining dependencies are met */
 
1254
        while (constrainedWindows)
 
1255
        {
 
1256
            constrainedWindows = FALSE;
 
1257
            /* loop through all windows and try to constrain their
 
1258
               animation path (going from gw->orgPos to
 
1259
               gw->destination) to the active screen area */
 
1260
            for (i = 0; i < group->nWins; i++)
 
1261
            {
 
1262
                CompWindow *w = group->windows[i];
1509
1263
                GROUP_WINDOW (w);
1510
1264
 
1511
 
                /* ignore certain windows: we don't want to apply the constraining
1512
 
                   results on the constrained window itself, nor do we want to
1513
 
                   change the target position of unamimated windows and of
1514
 
                   windows which already are constrained */
1515
 
                if (w->id == constrainedWindow)
1516
 
                        continue;
1517
 
 
 
1265
                /* ignore windows which aren't animated and/or
 
1266
                   already are at the edge of the screen area */
1518
1267
                if (!(gw->animateState & IS_ANIMATED))
1519
 
                        continue;
 
1268
                    continue;
1520
1269
 
1521
1270
                if (gw->animateState & DONT_CONSTRAIN)
1522
 
                        continue;
1523
 
 
1524
 
                if (!(gw->animateState & CONSTRAINED_X))
1525
 
                {
1526
 
                        gw->animateState |= IS_ANIMATED;
1527
 
 
1528
 
                        /* applying the constraining result of another window
1529
 
                           might move the window offscreen, too, so check
1530
 
                           if this is not the case */
1531
 
                        if (groupConstrainMovement (w, constrainRegion, dx, 0, &dx, NULL))
1532
 
                                gw->animateState |= CONSTRAINED_X;
1533
 
 
1534
 
                        gw->destination.x += dx;
1535
 
                        gw->orgPos.x += dx;
1536
 
                }
1537
 
 
1538
 
                if (!(gw->animateState & CONSTRAINED_Y))
1539
 
                {
1540
 
                        gw->animateState |= IS_ANIMATED;
1541
 
 
1542
 
                        /* analog to X case */
1543
 
                        if (groupConstrainMovement (w, constrainRegion, 0, dy, NULL, &dy))
1544
 
                                gw->animateState |= CONSTRAINED_Y;
1545
 
 
1546
 
                        gw->destination.y += dy;
1547
 
                        gw->orgPos.y += dy;
1548
 
                }
1549
 
        }
1550
 
}
1551
 
 
1552
 
/*
1553
 
 * groupStartTabbingAnimation
1554
 
 *
1555
 
 */
1556
 
void
1557
 
groupStartTabbingAnimation (GroupSelection *group,
1558
 
                                                        Bool           tab)
1559
 
{
1560
 
        CompScreen *s;
1561
 
        int        i;
1562
 
        int        dx, dy;
1563
 
        int        constrainStatus;
1564
 
 
1565
 
        if (!group || (group->tabbingState != PaintOff))
1566
 
                return;
1567
 
 
1568
 
        s = group->screen;
1569
 
        group->doTabbing = TRUE;
1570
 
        group->changeTab = TRUE;
1571
 
 
1572
 
        group->tabbingState = (tab) ? PaintFadeIn : PaintFadeOut;
1573
 
 
1574
 
        if (!tab)
1575
 
        {
1576
 
                /* we need to set up the X/Y constraining on untabbing */
1577
 
                Region constrainRegion = groupGetConstrainRegion (s);
1578
 
                Bool   constrainedWindows = TRUE;
1579
 
 
1580
 
                if (!constrainRegion)
1581
 
                        return;
1582
 
 
1583
 
                /* reset all flags */
1584
 
                for (i = 0; i < group->nWins; i++)
1585
 
                {
1586
 
                        GROUP_WINDOW (group->windows[i]);
1587
 
                        gw->animateState &= ~(CONSTRAINED_X | CONSTRAINED_Y |
1588
 
                                                                  DONT_CONSTRAIN);
1589
 
                }
1590
 
 
1591
 
                /* as we apply the constraining in a flat loop,
1592
 
                   we may need to run multiple times through this
1593
 
                   loop until all constraining dependencies are met */
1594
 
                while (constrainedWindows)
1595
 
                {
1596
 
                        constrainedWindows = FALSE;
1597
 
                        /* loop through all windows and try to constrain their
1598
 
                           animation path (going from gw->orgPos to
1599
 
                           gw->destination) to the active screen area */
1600
 
                        for (i = 0; i < group->nWins; i++)
1601
 
                        {
1602
 
                                CompWindow *w = group->windows[i];
1603
 
                                GROUP_WINDOW (w);
1604
 
 
1605
 
                                /* ignore windows which aren't animated and/or
1606
 
                                   already are at the edge of the screen area */
1607
 
                                if (!(gw->animateState & IS_ANIMATED))
1608
 
                                        continue;
1609
 
 
1610
 
                                if (gw->animateState & DONT_CONSTRAIN)
1611
 
                                        continue;
1612
 
 
1613
 
                                /* is the original position inside the screen area? */
1614
 
                                constrainStatus = XRectInRegion (constrainRegion,
1615
 
                                                                                                 gw->orgPos.x  - w->input.left,
1616
 
                                                                                                 gw->orgPos.y - w->input.top,
1617
 
                                                                                                 WIN_REAL_WIDTH (w),
1618
 
                                                                                                 WIN_REAL_HEIGHT (w));
1619
 
 
1620
 
                                /* constrain the movement */
1621
 
                                if (groupConstrainMovement (w, constrainRegion,
1622
 
                                                                                        gw->destination.x - gw->orgPos.x,
1623
 
                                                                                        gw->destination.y - gw->orgPos.y,
1624
 
                                                                                        &dx, &dy))
1625
 
                                {
1626
 
                                        /* handle the case where the window is outside the screen
1627
 
                                           area on its whole animation path */
1628
 
                                        if (constrainStatus != RectangleIn && !dx && !dy)
1629
 
                                        {
1630
 
                                                gw->animateState |= DONT_CONSTRAIN;
1631
 
                                                gw->animateState |= CONSTRAINED_X | CONSTRAINED_Y;
1632
 
 
1633
 
                                                /* use the original position as last resort */
1634
 
                                                gw->destination.x = gw->mainTabOffset.x;
1635
 
                                                gw->destination.y = gw->mainTabOffset.y;
1636
 
                                        }
1637
 
                                        else
1638
 
                                        {
1639
 
                                                /* if we found a valid target position, apply
1640
 
                                                   the change also to other windows to retain
1641
 
                                                   the distance between the windows */
1642
 
                                                groupApplyConstrainingToWindows (group,
1643
 
                                                                                                                 constrainRegion,
1644
 
                                                                                                                 w->id,
1645
 
                                                                                                                 dx -
1646
 
                                                                                                                 gw->destination.x +
1647
 
                                                                                                                 gw->orgPos.x,
1648
 
                                                                                                                 dy -
1649
 
                                                                                                                 gw->destination.y +
1650
 
                                                                                                                 gw->orgPos.y);
1651
 
 
1652
 
                                                /* if we hit constraints, adjust the mask and the
1653
 
                                                   target position accordingly */
1654
 
                                                if (dx != (gw->destination.x - gw->orgPos.x))
1655
 
                                                {
1656
 
                                                        gw->animateState |= CONSTRAINED_X;
1657
 
                                                        gw->destination.x = gw->orgPos.x + dx;
1658
 
                                                }
1659
 
 
1660
 
                                                if (dy != (gw->destination.y - gw->orgPos.y))
1661
 
                                                {
1662
 
                                                        gw->animateState |= CONSTRAINED_Y;
1663
 
                                                        gw->destination.y = gw->orgPos.y + dy;
1664
 
                                                }
1665
 
 
1666
 
                                                constrainedWindows = TRUE;
1667
 
                                        }
1668
 
                                }
1669
 
                        }
1670
 
                }
1671
 
                XDestroyRegion (constrainRegion);
1672
 
        }
 
1271
                    continue;
 
1272
 
 
1273
                /* is the original position inside the screen area? */
 
1274
                constrainStatus = XRectInRegion (constrainRegion,
 
1275
                                                 gw->orgPos.x  - w->input.left,
 
1276
                                                 gw->orgPos.y - w->input.top,
 
1277
                                                 WIN_REAL_WIDTH (w),
 
1278
                                                 WIN_REAL_HEIGHT (w));
 
1279
 
 
1280
                /* constrain the movement */
 
1281
                if (groupConstrainMovement (w, constrainRegion,
 
1282
                                            gw->destination.x - gw->orgPos.x,
 
1283
                                            gw->destination.y - gw->orgPos.y,
 
1284
                                            &dx, &dy))
 
1285
                {
 
1286
                    /* handle the case where the window is outside the screen
 
1287
                       area on its whole animation path */
 
1288
                    if (constrainStatus != RectangleIn && !dx && !dy)
 
1289
                    {
 
1290
                        gw->animateState |= DONT_CONSTRAIN;
 
1291
                        gw->animateState |= CONSTRAINED_X | CONSTRAINED_Y;
 
1292
 
 
1293
                        /* use the original position as last resort */
 
1294
                        gw->destination.x = gw->mainTabOffset.x;
 
1295
                        gw->destination.y = gw->mainTabOffset.y;
 
1296
                    }
 
1297
                    else
 
1298
                    {
 
1299
                        /* if we found a valid target position, apply
 
1300
                           the change also to other windows to retain
 
1301
                           the distance between the windows */
 
1302
                        groupApplyConstraining (group, constrainRegion, w->id,
 
1303
                                                dx - gw->destination.x +
 
1304
                                                gw->orgPos.x,
 
1305
                                                dy - gw->destination.y +
 
1306
                                                gw->orgPos.y);
 
1307
 
 
1308
                        /* if we hit constraints, adjust the mask and the
 
1309
                           target position accordingly */
 
1310
                        if (dx != (gw->destination.x - gw->orgPos.x))
 
1311
                        {
 
1312
                            gw->animateState |= CONSTRAINED_X;
 
1313
                            gw->destination.x = gw->orgPos.x + dx;
 
1314
                        }
 
1315
 
 
1316
                        if (dy != (gw->destination.y - gw->orgPos.y))
 
1317
                        {
 
1318
                            gw->animateState |= CONSTRAINED_Y;
 
1319
                            gw->destination.y = gw->orgPos.y + dy;
 
1320
                        }
 
1321
 
 
1322
                        constrainedWindows = TRUE;
 
1323
                    }
 
1324
                }
 
1325
            }
 
1326
        }
 
1327
        XDestroyRegion (constrainRegion);
 
1328
    }
1673
1329
}
1674
1330
 
1675
1331
/*
1679
1335
void
1680
1336
groupTabGroup (CompWindow *main)
1681
1337
{
1682
 
        GroupSelection  *group;
1683
 
        GroupTabBarSlot *slot;
1684
 
        int             width, height;
1685
 
        int             space, thumbSize;
1686
 
 
1687
 
        GROUP_WINDOW (main);
1688
 
 
1689
 
        group = gw->group;
1690
 
        if (!group || group->tabBar)
1691
 
                return;
1692
 
 
1693
 
        if (!main->screen->display->shapeExtension)
1694
 
        {
1695
 
                compLogMessage (main->screen->display, "group", CompLogLevelError,
1696
 
                                                "No X shape extension! Tabbing disabled.");
1697
 
                return;
1698
 
        }
1699
 
 
1700
 
        groupInitTabBar (group, main);
1701
 
        if (!group->tabBar)
1702
 
                return;
1703
 
 
1704
 
        groupCreateInputPreventionWindow (group);
1705
 
 
1706
 
        group->tabbingState = PaintOff;
1707
 
        /* Slot is initialized after groupInitTabBar(group); */
1708
 
        groupChangeTab (gw->slot, RotateUncertain);
1709
 
        groupRecalcTabBarPos (gw->group,
1710
 
                                                  WIN_X (main) + WIN_WIDTH (main) / 2,
1711
 
                                                  WIN_X (main), WIN_X (main) + WIN_WIDTH (main));
1712
 
 
1713
 
        width = group->tabBar->region->extents.x2 -
1714
 
                    group->tabBar->region->extents.x1;
1715
 
        height = group->tabBar->region->extents.y2 -
1716
 
                     group->tabBar->region->extents.y1;
1717
 
 
1718
 
        group->tabBar->textLayer = groupCreateCairoLayer (main->screen,
1719
 
                                                                                                          width, height);
1720
 
        if (group->tabBar->textLayer)
1721
 
        {
1722
 
                GroupCairoLayer *layer;
1723
 
 
1724
 
                layer = group->tabBar->textLayer;
1725
 
                layer->state = PaintOff;
1726
 
                layer->animationTime = 0;
1727
 
                groupRenderWindowTitle (group);
1728
 
        }
1729
 
        if (group->tabBar->textLayer)
1730
 
        {
1731
 
                GroupCairoLayer *layer;
1732
 
                
1733
 
                layer = group->tabBar->textLayer;
1734
 
                layer->animationTime = groupGetFadeTextTime (main->screen) *
1735
 
                                       1000;
1736
 
                layer->state = PaintFadeIn;
1737
 
        }
1738
 
 
1739
 
        // we need a buffer for DnD here
1740
 
        space = groupGetThumbSpace (main->screen);
1741
 
        thumbSize = groupGetThumbSize (main->screen);
1742
 
        group->tabBar->bgLayer = groupCreateCairoLayer (main->screen,
1743
 
                                                                                                        width + space + thumbSize,
1744
 
                                                                                                        height);
1745
 
        if (group->tabBar->bgLayer)
1746
 
        {
1747
 
                group->tabBar->bgLayer->state = PaintOn;
1748
 
                group->tabBar->bgLayer->animationTime = 0;
1749
 
                groupRenderTabBarBackground (group);
1750
 
        }
1751
 
 
1752
 
        width = group->topTab->region->extents.x2 -
1753
 
                    group->topTab->region->extents.x1;
1754
 
        height = group->topTab->region->extents.y2 -
1755
 
                     group->topTab->region->extents.y1;
1756
 
 
1757
 
        group->tabBar->selectionLayer = groupCreateCairoLayer (main->screen,
1758
 
                                                                                                                   width, height);
1759
 
        if (group->tabBar->selectionLayer)
1760
 
        {
1761
 
                group->tabBar->selectionLayer->state = PaintOn;
1762
 
                group->tabBar->selectionLayer->animationTime = 0;
1763
 
                groupRenderTopTabHighlight (group);
1764
 
        }
1765
 
 
1766
 
        if (!HAS_TOP_WIN (group))
1767
 
                return;
1768
 
 
1769
 
        for (slot = group->tabBar->slots; slot; slot = slot->next)
1770
 
        {
1771
 
                CompWindow *cw = slot->window;
1772
 
 
1773
 
                GROUP_WINDOW (cw);
1774
 
 
1775
 
                if (gw->animateState & (IS_ANIMATED | FINISHED_ANIMATION))
1776
 
                        moveWindow (cw,
1777
 
                                                gw->destination.x - WIN_X (cw),
1778
 
                                                gw->destination.y - WIN_Y (cw),
1779
 
                                                FALSE, TRUE);
1780
 
 
1781
 
                /* center the window to the main window */
1782
 
                gw->destination.x = WIN_X (main) +
1783
 
                                        (WIN_WIDTH (main) / 2) - (WIN_WIDTH (cw) / 2);
1784
 
                gw->destination.y = WIN_Y (main) +
1785
 
                                        (WIN_HEIGHT (main) / 2) - (WIN_HEIGHT (cw) / 2);
1786
 
 
1787
 
                /* Distance from destination. */
1788
 
                gw->mainTabOffset.x = WIN_X (cw) - gw->destination.x;
1789
 
                gw->mainTabOffset.y = WIN_Y (cw) - gw->destination.y;
1790
 
 
1791
 
                if (gw->tx || gw->ty)
1792
 
                {
1793
 
                        gw->tx -= (WIN_X (cw) - gw->orgPos.x);
1794
 
                        gw->ty -= (WIN_Y (cw) - gw->orgPos.y);
1795
 
                }
1796
 
 
1797
 
                gw->orgPos.x = WIN_X (cw);
1798
 
                gw->orgPos.y = WIN_Y (cw);
1799
 
 
1800
 
                gw->animateState = IS_ANIMATED;
1801
 
                gw->xVelocity = gw->yVelocity = 0.0f;
1802
 
        }
1803
 
 
1804
 
        groupStartTabbingAnimation (group, TRUE);
 
1338
    GroupSelection  *group;
 
1339
    GroupTabBarSlot *slot;
 
1340
    CompScreen      *s = main->screen;
 
1341
    int             width, height;
 
1342
    int             space, thumbSize;
 
1343
 
 
1344
    GROUP_WINDOW (main);
 
1345
 
 
1346
    group = gw->group;
 
1347
    if (!group || group->tabBar)
 
1348
        return;
 
1349
 
 
1350
    if (!s->display->shapeExtension)
 
1351
    {
 
1352
        compLogMessage (s->display, "group", CompLogLevelError,
 
1353
                        "No X shape extension! Tabbing disabled.");
 
1354
        return;
 
1355
    }
 
1356
 
 
1357
    groupInitTabBar (group, main);
 
1358
    if (!group->tabBar)
 
1359
        return;
 
1360
 
 
1361
    groupCreateInputPreventionWindow (group);
 
1362
 
 
1363
    group->tabbingState = NoTabbing;
 
1364
    /* Slot is initialized after groupInitTabBar(group); */
 
1365
    groupChangeTab (gw->slot, RotateUncertain);
 
1366
    groupRecalcTabBarPos (gw->group, WIN_CENTER_X (main),
 
1367
                          WIN_X (main), WIN_X (main) + WIN_WIDTH (main));
 
1368
 
 
1369
    width = group->tabBar->region->extents.x2 -
 
1370
            group->tabBar->region->extents.x1;
 
1371
    height = group->tabBar->region->extents.y2 -
 
1372
             group->tabBar->region->extents.y1;
 
1373
 
 
1374
    group->tabBar->textLayer = groupCreateCairoLayer (s, width, height);
 
1375
    if (group->tabBar->textLayer)
 
1376
    {
 
1377
        GroupCairoLayer *layer;
 
1378
 
 
1379
        layer = group->tabBar->textLayer;
 
1380
        layer->state = PaintOff;
 
1381
        layer->animationTime = 0;
 
1382
        groupRenderWindowTitle (group);
 
1383
    }
 
1384
    if (group->tabBar->textLayer)
 
1385
    {
 
1386
        GroupCairoLayer *layer;
 
1387
 
 
1388
        layer = group->tabBar->textLayer;
 
1389
        layer->animationTime = groupGetFadeTextTime (s) * 1000;
 
1390
        layer->state = PaintFadeIn;
 
1391
    }
 
1392
 
 
1393
    /* we need a buffer for DnD here */
 
1394
    space = groupGetThumbSpace (s);
 
1395
    thumbSize = groupGetThumbSize (s);
 
1396
    group->tabBar->bgLayer = groupCreateCairoLayer (s,
 
1397
                                                    width + space + thumbSize,
 
1398
                                                    height);
 
1399
    if (group->tabBar->bgLayer)
 
1400
    {
 
1401
        group->tabBar->bgLayer->state = PaintOn;
 
1402
        group->tabBar->bgLayer->animationTime = 0;
 
1403
        groupRenderTabBarBackground (group);
 
1404
    }
 
1405
 
 
1406
    width = group->topTab->region->extents.x2 -
 
1407
            group->topTab->region->extents.x1;
 
1408
    height = group->topTab->region->extents.y2 -
 
1409
             group->topTab->region->extents.y1;
 
1410
 
 
1411
    group->tabBar->selectionLayer = groupCreateCairoLayer (s, width, height);
 
1412
    if (group->tabBar->selectionLayer)
 
1413
    {
 
1414
        group->tabBar->selectionLayer->state = PaintOn;
 
1415
        group->tabBar->selectionLayer->animationTime = 0;
 
1416
        groupRenderTopTabHighlight (group);
 
1417
    }
 
1418
 
 
1419
    if (!HAS_TOP_WIN (group))
 
1420
        return;
 
1421
 
 
1422
    for (slot = group->tabBar->slots; slot; slot = slot->next)
 
1423
    {
 
1424
        CompWindow *cw = slot->window;
 
1425
 
 
1426
        GROUP_WINDOW (cw);
 
1427
 
 
1428
        if (gw->animateState & (IS_ANIMATED | FINISHED_ANIMATION))
 
1429
            moveWindow (cw,
 
1430
                        gw->destination.x - WIN_X (cw),
 
1431
                        gw->destination.y - WIN_Y (cw),
 
1432
                        FALSE, TRUE);
 
1433
 
 
1434
        /* center the window to the main window */
 
1435
        gw->destination.x = WIN_CENTER_X (main) - (WIN_WIDTH (cw) / 2);
 
1436
        gw->destination.y = WIN_CENTER_Y (main) - (WIN_HEIGHT (cw) / 2);
 
1437
 
 
1438
        /* Distance from destination. */
 
1439
        gw->mainTabOffset.x = WIN_X (cw) - gw->destination.x;
 
1440
        gw->mainTabOffset.y = WIN_Y (cw) - gw->destination.y;
 
1441
 
 
1442
        if (gw->tx || gw->ty)
 
1443
        {
 
1444
            gw->tx -= (WIN_X (cw) - gw->orgPos.x);
 
1445
            gw->ty -= (WIN_Y (cw) - gw->orgPos.y);
 
1446
        }
 
1447
 
 
1448
        gw->orgPos.x = WIN_X (cw);
 
1449
        gw->orgPos.y = WIN_Y (cw);
 
1450
 
 
1451
        gw->animateState = IS_ANIMATED;
 
1452
        gw->xVelocity = gw->yVelocity = 0.0f;
 
1453
    }
 
1454
 
 
1455
    groupStartTabbingAnimation (group, TRUE);
1805
1456
}
1806
1457
 
1807
1458
/*
1809
1460
 *
1810
1461
 */
1811
1462
void
1812
 
groupUntabGroup(GroupSelection *group)
 
1463
groupUntabGroup (GroupSelection *group)
1813
1464
{
1814
 
        int             oldX, oldY;
1815
 
        CompWindow      *prevTopTab;
1816
 
        GroupTabBarSlot *slot;
1817
 
 
1818
 
        if (!HAS_TOP_WIN (group))
1819
 
                return;
1820
 
 
1821
 
        GROUP_SCREEN (TOP_TAB (group)->screen);
1822
 
 
1823
 
        if (group->prevTopTab)
1824
 
                prevTopTab = PREV_TOP_TAB (group);
1825
 
        else
1826
 
        {
1827
 
                /* If prevTopTab isn't set, we have no choice but using topTab.
1828
 
                   It happens when there is still animation, which
1829
 
                   means the tab wasn't changed anyway. */
1830
 
                prevTopTab = TOP_TAB (group);
1831
 
        }
1832
 
 
1833
 
        group->oldTopTabCenterX = WIN_X (prevTopTab) + WIN_WIDTH (prevTopTab) / 2;
1834
 
        group->oldTopTabCenterY = WIN_Y (prevTopTab) + WIN_HEIGHT (prevTopTab) / 2;
1835
 
 
1836
 
        group->lastTopTab = TOP_TAB (group);
1837
 
        group->topTab = NULL;
1838
 
 
1839
 
        for (slot = group->tabBar->slots; slot; slot = slot->next)
1840
 
        {
1841
 
                CompWindow *cw = slot->window;
1842
 
 
1843
 
                GROUP_WINDOW (cw);
1844
 
 
1845
 
                gs->queued = TRUE;
1846
 
                groupSetWindowVisibility (cw, TRUE);
1847
 
                if (gw->animateState & (IS_ANIMATED | FINISHED_ANIMATION))
1848
 
                        moveWindow (cw,
1849
 
                                                gw->destination.x - WIN_X (cw),
1850
 
                                                gw->destination.y - WIN_Y (cw),
1851
 
                                                FALSE, TRUE);
1852
 
                moveWindow (cw,
1853
 
                                        group->oldTopTabCenterX - WIN_X (cw) - WIN_WIDTH (cw) / 2,
1854
 
                                        group->oldTopTabCenterY - WIN_Y (cw) - WIN_HEIGHT (cw) / 2,
1855
 
                                        FALSE, TRUE);
1856
 
                syncWindowPosition (cw);
1857
 
                gs->queued = FALSE;
1858
 
 
1859
 
                /* save the old original position - we might need it
1860
 
                   if constraining fails */
1861
 
                oldX = gw->orgPos.x;
1862
 
                oldY = gw->orgPos.y;
1863
 
 
1864
 
                gw->orgPos.x = group->oldTopTabCenterX - WIN_WIDTH (cw) / 2;
1865
 
                gw->orgPos.y = group->oldTopTabCenterY - WIN_HEIGHT (cw) / 2;
1866
 
 
1867
 
                gw->destination.x = gw->orgPos.x + gw->mainTabOffset.x;
1868
 
                gw->destination.y = gw->orgPos.y + gw->mainTabOffset.y;
1869
 
        
1870
 
                if (gw->tx || gw->ty)
1871
 
                {
1872
 
                        gw->tx -= (gw->orgPos.x - oldX);
1873
 
                        gw->ty -= (gw->orgPos.y - oldY);
1874
 
                }
1875
 
 
1876
 
                gw->mainTabOffset.x = oldX;
1877
 
                gw->mainTabOffset.y = oldY;
1878
 
 
1879
 
                gw->animateState = IS_ANIMATED;
1880
 
                gw->xVelocity = gw->yVelocity = 0.0f;
1881
 
        }
1882
 
 
1883
 
        group->tabbingState = PaintOff;
1884
 
        groupStartTabbingAnimation (group, FALSE);
1885
 
 
1886
 
        damageScreen (group->screen);
 
1465
    int             oldX, oldY;
 
1466
    CompWindow      *prevTopTab;
 
1467
    GroupTabBarSlot *slot;
 
1468
 
 
1469
    if (!HAS_TOP_WIN (group))
 
1470
        return;
 
1471
 
 
1472
    GROUP_SCREEN (group->screen);
 
1473
 
 
1474
    if (group->prevTopTab)
 
1475
        prevTopTab = PREV_TOP_TAB (group);
 
1476
    else
 
1477
    {
 
1478
        /* If prevTopTab isn't set, we have no choice but using topTab.
 
1479
           It happens when there is still animation, which
 
1480
           means the tab wasn't changed anyway. */
 
1481
        prevTopTab = TOP_TAB (group);
 
1482
    }
 
1483
 
 
1484
    group->lastTopTab = TOP_TAB (group);
 
1485
    group->topTab = NULL;
 
1486
 
 
1487
    for (slot = group->tabBar->slots; slot; slot = slot->next)
 
1488
    {
 
1489
        CompWindow *cw = slot->window;
 
1490
 
 
1491
        GROUP_WINDOW (cw);
 
1492
 
 
1493
        if (gw->animateState & (IS_ANIMATED | FINISHED_ANIMATION))
 
1494
        {
 
1495
            gs->queued = TRUE;
 
1496
            moveWindow (cw,
 
1497
                        gw->destination.x - WIN_X (cw),
 
1498
                        gw->destination.y - WIN_Y (cw),
 
1499
                        FALSE, TRUE);
 
1500
            gs->queued = FALSE;
 
1501
        }
 
1502
        groupSetWindowVisibility (cw, TRUE);
 
1503
 
 
1504
        /* save the old original position - we might need it
 
1505
           if constraining fails */
 
1506
        oldX = gw->orgPos.x;
 
1507
        oldY = gw->orgPos.y;
 
1508
 
 
1509
        gw->orgPos.x = WIN_CENTER_X (prevTopTab) - WIN_WIDTH (cw) / 2;
 
1510
        gw->orgPos.y = WIN_CENTER_Y (prevTopTab) - WIN_HEIGHT (cw) / 2;
 
1511
 
 
1512
        gw->destination.x = gw->orgPos.x + gw->mainTabOffset.x;
 
1513
        gw->destination.y = gw->orgPos.y + gw->mainTabOffset.y;
 
1514
 
 
1515
        if (gw->tx || gw->ty)
 
1516
        {
 
1517
            gw->tx -= (gw->orgPos.x - oldX);
 
1518
            gw->ty -= (gw->orgPos.y - oldY);
 
1519
        }
 
1520
 
 
1521
        gw->mainTabOffset.x = oldX;
 
1522
        gw->mainTabOffset.y = oldY;
 
1523
 
 
1524
        gw->animateState = IS_ANIMATED;
 
1525
        gw->xVelocity = gw->yVelocity = 0.0f;
 
1526
    }
 
1527
 
 
1528
    group->tabbingState = NoTabbing;
 
1529
    groupStartTabbingAnimation (group, FALSE);
 
1530
 
 
1531
    groupDeleteTabBar (group);
 
1532
    group->changeAnimationTime = 0;
 
1533
    group->changeState = NoTabChange;
 
1534
    group->nextTopTab = NULL;
 
1535
    group->prevTopTab = NULL;
 
1536
 
 
1537
    damageScreen (group->screen);
1887
1538
}
1888
1539
 
1889
1540
/*
1892
1543
 */
1893
1544
Bool
1894
1545
groupChangeTab (GroupTabBarSlot             *topTab,
1895
 
                                ChangeTabAnimationDirection direction)
1896
 
{
1897
 
        CompWindow     *w;
1898
 
        GroupSelection *group;
1899
 
 
1900
 
        if (!topTab)
1901
 
                return TRUE;
1902
 
 
1903
 
        GROUP_WINDOW (topTab->window);
1904
 
 
1905
 
        w = topTab->window;
1906
 
        group = gw->group;
1907
 
 
1908
 
        if (!group || group->tabbingState != PaintOff)
1909
 
                return TRUE;
1910
 
 
1911
 
        if (group->changeState == PaintOff && group->topTab == topTab)
1912
 
                return TRUE;
1913
 
 
1914
 
        if (group->changeState != PaintOff && group->nextTopTab == topTab)
1915
 
                return TRUE;
1916
 
 
1917
 
        if (group->prevTopTab && group->changeState == PaintOff)
1918
 
        {
1919
 
                group->oldTopTabCenterX = WIN_X (PREV_TOP_TAB (group)) +
1920
 
                                              WIN_WIDTH (PREV_TOP_TAB (group)) / 2;
1921
 
                group->oldTopTabCenterY = WIN_Y (PREV_TOP_TAB (group)) +
1922
 
                                              WIN_HEIGHT (PREV_TOP_TAB (group)) / 2;
1923
 
        }
1924
 
 
1925
 
        if (group->changeState != PaintOff)
1926
 
                group->nextDirection = direction;
1927
 
        else if (direction == RotateLeft)
1928
 
                group->changeAnimationDirection = 1;
1929
 
        else if (direction == RotateRight)
1930
 
                group->changeAnimationDirection = -1;
1931
 
        else
1932
 
        {
1933
 
                int             distanceOld = 0, distanceNew = 0;
1934
 
                GroupTabBarSlot *slot;
1935
 
 
1936
 
                if (group->topTab)
1937
 
                        for (slot = group->tabBar->slots; slot && (slot != group->topTab);
1938
 
                                 slot = slot->next, distanceOld++);
1939
 
 
1940
 
                for (slot = group->tabBar->slots; slot && (slot != topTab);
1941
 
                         slot = slot->next, distanceNew++);
1942
 
 
1943
 
                if (distanceNew < distanceOld)
1944
 
                        group->changeAnimationDirection = 1;   /*left */
1945
 
                else
1946
 
                        group->changeAnimationDirection = -1;  /* right */
1947
 
 
1948
 
                /* check if the opposite direction is shorter */
1949
 
                if (abs (distanceNew - distanceOld) > (group->tabBar->nSlots / 2))
1950
 
                        group->changeAnimationDirection *= -1;
1951
 
        }
1952
 
 
1953
 
        if (group->changeState != PaintOff)
1954
 
        {
1955
 
                if (group->prevTopTab == topTab)
1956
 
                {
1957
 
                        /* Reverse animation. */
1958
 
                        GroupTabBarSlot *tmp = group->topTab;
1959
 
                        group->topTab = group->prevTopTab;
1960
 
                        group->prevTopTab = tmp;
1961
 
 
1962
 
                        group->changeAnimationDirection *= -1;
1963
 
                        group->changeAnimationTime =
1964
 
                                groupGetChangeAnimationTime (w->screen) * 500 -
1965
 
                                group->changeAnimationTime;
1966
 
                        group->changeState =
1967
 
                                (group->changeState == PaintFadeIn) ? PaintFadeOut: PaintFadeIn;
1968
 
 
1969
 
                        group->nextTopTab = NULL;
1970
 
                }
1971
 
                else
1972
 
                        group->nextTopTab = topTab;
1973
 
        }
1974
 
        else
1975
 
        {
1976
 
                group->topTab = topTab;
1977
 
                group->changeTab = (group->prevTopTab != topTab);
1978
 
 
1979
 
                groupRenderWindowTitle (group);
1980
 
                groupRenderTopTabHighlight (group);
1981
 
                addWindowDamage (w);
1982
 
        }
1983
 
 
1984
 
        return TRUE;
1985
 
}
1986
 
 
1987
 
/*
1988
 
 * groupRebuildCairoLayer
1989
 
 *
1990
 
 */
1991
 
GroupCairoLayer*
1992
 
groupRebuildCairoLayer (CompScreen      *s,
1993
 
                                                GroupCairoLayer *layer,
1994
 
                                                int             width,
1995
 
                                                int             height)
1996
 
{
1997
 
        int        timeBuf = layer->animationTime;
1998
 
        PaintState stateBuf = layer->state;
1999
 
 
2000
 
        groupDestroyCairoLayer (s, layer);
2001
 
        layer = groupCreateCairoLayer (s, width, height);
2002
 
        if (!layer)
2003
 
                return NULL;
2004
 
 
2005
 
        layer->animationTime = timeBuf;
2006
 
        layer->state = stateBuf;
2007
 
 
2008
 
        return layer;
2009
 
}
2010
 
 
2011
 
/*
2012
 
 * groupClearCairoLayer
2013
 
 *
2014
 
 */
2015
 
void
2016
 
groupClearCairoLayer (GroupCairoLayer *layer)
2017
 
{
2018
 
        cairo_t *cr = layer->cairo;
2019
 
 
2020
 
        cairo_save (cr);
2021
 
        cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
2022
 
        cairo_paint (cr);
2023
 
        cairo_restore (cr);
2024
 
}
2025
 
 
2026
 
/*
2027
 
 * groupDestroyCairoLayer
2028
 
 *
2029
 
 */
2030
 
void
2031
 
groupDestroyCairoLayer (CompScreen      *s,
2032
 
                                                GroupCairoLayer *layer)
2033
 
{
2034
 
        if (layer->cairo)
2035
 
                cairo_destroy (layer->cairo);
2036
 
 
2037
 
        if (layer->surface)
2038
 
                cairo_surface_destroy (layer->surface);
2039
 
 
2040
 
        finiTexture (s, &layer->texture);
2041
 
        
2042
 
        if (layer->buffer)
2043
 
                free (layer->buffer);
2044
 
 
2045
 
        free (layer);
2046
 
}
2047
 
 
2048
 
/*
2049
 
 * groupCreateCairoLayer
2050
 
 *
2051
 
 */
2052
 
GroupCairoLayer*
2053
 
groupCreateCairoLayer (CompScreen *s,
2054
 
                                           int        width,
2055
 
                                           int        height)
2056
 
{
2057
 
        GroupCairoLayer *layer;
2058
 
 
2059
 
        
2060
 
        layer = malloc (sizeof (GroupCairoLayer));
2061
 
 
2062
 
        layer->surface  = NULL;
2063
 
        layer->cairo    = NULL;
2064
 
        layer->buffer   = NULL;
2065
 
        layer->animationTime = 0;
2066
 
        layer->state = PaintOff;
2067
 
        layer->texWidth = width;
2068
 
        layer->texHeight = height;
2069
 
 
2070
 
        initTexture (s, &layer->texture);
2071
 
 
2072
 
        layer->buffer = calloc (4 * width * height, sizeof (unsigned char));
2073
 
        if (!layer->buffer)
2074
 
        {
2075
 
                printf ("ERROR: Failed to alloc buffer!\n");
2076
 
                groupDestroyCairoLayer (s, layer);
2077
 
                return NULL;
2078
 
        }
2079
 
 
2080
 
        layer->surface = cairo_image_surface_create_for_data (layer->buffer,
2081
 
                                                                                                                  CAIRO_FORMAT_ARGB32,
2082
 
                                                                                                                  width, height,
2083
 
                                                                                                                  4 * width);
2084
 
        if (cairo_surface_status (layer->surface) != CAIRO_STATUS_SUCCESS)
2085
 
        {
2086
 
                printf ("ERROR: Failed to create surface!\n");
2087
 
                groupDestroyCairoLayer (s, layer);
2088
 
        return NULL;
2089
 
        }
2090
 
 
2091
 
        layer->cairo = cairo_create (layer->surface);
2092
 
        if (cairo_status (layer->cairo) != CAIRO_STATUS_SUCCESS)
2093
 
        {
2094
 
                printf ("ERROR: Failed to create context!\n");
2095
 
                groupDestroyCairoLayer (s, layer);
2096
 
        return NULL;
2097
 
        }
2098
 
 
2099
 
        groupClearCairoLayer (layer);
2100
 
 
2101
 
        return layer;
 
1546
                ChangeTabAnimationDirection direction)
 
1547
{
 
1548
    CompWindow     *w, *oldTopTab;
 
1549
    GroupSelection *group;
 
1550
 
 
1551
    if (!topTab)
 
1552
        return TRUE;
 
1553
 
 
1554
    w = topTab->window;
 
1555
 
 
1556
    GROUP_WINDOW (w);
 
1557
 
 
1558
    group = gw->group;
 
1559
 
 
1560
    if (!group || group->tabbingState != NoTabbing)
 
1561
        return TRUE;
 
1562
 
 
1563
    if (group->changeState == NoTabChange && group->topTab == topTab)
 
1564
        return TRUE;
 
1565
 
 
1566
    if (group->changeState != NoTabChange && group->nextTopTab == topTab)
 
1567
        return TRUE;
 
1568
 
 
1569
    oldTopTab = group->topTab ? group->topTab->window : NULL;
 
1570
 
 
1571
    if (group->changeState != NoTabChange)
 
1572
        group->nextDirection = direction;
 
1573
    else if (direction == RotateLeft)
 
1574
        group->changeAnimationDirection = 1;
 
1575
    else if (direction == RotateRight)
 
1576
        group->changeAnimationDirection = -1;
 
1577
    else
 
1578
    {
 
1579
        int             distanceOld = 0, distanceNew = 0;
 
1580
        GroupTabBarSlot *slot;
 
1581
 
 
1582
        if (group->topTab)
 
1583
            for (slot = group->tabBar->slots; slot && (slot != group->topTab);
 
1584
                 slot = slot->next, distanceOld++);
 
1585
 
 
1586
        for (slot = group->tabBar->slots; slot && (slot != topTab);
 
1587
             slot = slot->next, distanceNew++);
 
1588
 
 
1589
        if (distanceNew < distanceOld)
 
1590
            group->changeAnimationDirection = 1;   /*left */
 
1591
        else
 
1592
            group->changeAnimationDirection = -1;  /* right */
 
1593
 
 
1594
        /* check if the opposite direction is shorter */
 
1595
        if (abs (distanceNew - distanceOld) > (group->tabBar->nSlots / 2))
 
1596
            group->changeAnimationDirection *= -1;
 
1597
    }
 
1598
 
 
1599
    if (group->changeState != NoTabChange)
 
1600
    {
 
1601
        if (group->prevTopTab == topTab)
 
1602
        {
 
1603
            /* Reverse animation. */
 
1604
            GroupTabBarSlot *tmp = group->topTab;
 
1605
            group->topTab = group->prevTopTab;
 
1606
            group->prevTopTab = tmp;
 
1607
 
 
1608
            group->changeAnimationDirection *= -1;
 
1609
            group->changeAnimationTime =
 
1610
                groupGetChangeAnimationTime (w->screen) * 500 -
 
1611
                group->changeAnimationTime;
 
1612
            group->changeState = (group->changeState == TabChangeOldOut) ?
 
1613
                TabChangeNewIn : TabChangeOldOut;
 
1614
 
 
1615
            group->nextTopTab = NULL;
 
1616
        }
 
1617
        else
 
1618
            group->nextTopTab = topTab;
 
1619
    }
 
1620
    else
 
1621
    {
 
1622
        group->topTab = topTab;
 
1623
 
 
1624
        groupRenderWindowTitle (group);
 
1625
        groupRenderTopTabHighlight (group);
 
1626
        addWindowDamage (w);
 
1627
    }
 
1628
 
 
1629
    if (topTab != group->nextTopTab)
 
1630
    {
 
1631
        groupSetWindowVisibility (w, TRUE);
 
1632
        if (oldTopTab)
 
1633
        {
 
1634
            int dx, dy;
 
1635
 
 
1636
            GROUP_SCREEN (w->screen);
 
1637
 
 
1638
            dx = WIN_CENTER_X (oldTopTab) - WIN_CENTER_X (w);
 
1639
            dy = WIN_CENTER_Y (oldTopTab) - WIN_CENTER_Y (w);
 
1640
 
 
1641
            gs->queued = TRUE;
 
1642
            moveWindow (w, dx, dy, FALSE, TRUE);
 
1643
            syncWindowPosition (w);
 
1644
            gs->queued = FALSE;
 
1645
        }
 
1646
 
 
1647
        if (HAS_PREV_TOP_WIN (group))
 
1648
        {
 
1649
            /* we use only the half time here -
 
1650
               the second half will be PaintFadeOut */
 
1651
            group->changeAnimationTime =
 
1652
                groupGetChangeAnimationTime (w->screen) * 500;
 
1653
            groupTabChangeActivateEvent (w->screen, TRUE);
 
1654
            group->changeState = TabChangeOldOut;
 
1655
        }
 
1656
        else
 
1657
        {
 
1658
            /* No window to do animation with. */
 
1659
            if (HAS_TOP_WIN (group))
 
1660
                group->prevTopTab = group->topTab;
 
1661
            else
 
1662
                group->prevTopTab = NULL;
 
1663
            activateWindow (w);
 
1664
        }
 
1665
    }
 
1666
 
 
1667
    return TRUE;
2102
1668
}
2103
1669
 
2104
1670
/*
2107
1673
 */
2108
1674
static void
2109
1675
groupRecalcSlotPos (GroupTabBarSlot *slot,
2110
 
                                        int             slotPos)
 
1676
                    int             slotPos)
2111
1677
{
2112
 
        GroupSelection *group;
2113
 
        XRectangle     box;
2114
 
        int            space, thumbSize;
2115
 
 
2116
 
        GROUP_WINDOW (slot->window);
2117
 
        group = gw->group;
2118
 
 
2119
 
        if (!HAS_TOP_WIN (group) || !group->tabBar)
2120
 
                return;
2121
 
 
2122
 
        space = groupGetThumbSpace (slot->window->screen);
2123
 
        thumbSize = groupGetThumbSize (slot->window->screen);
2124
 
 
2125
 
        EMPTY_REGION (slot->region);
2126
 
 
2127
 
        box.x = space + ((thumbSize + space) * slotPos);
2128
 
        box.y = space;
2129
 
 
2130
 
        box.width = thumbSize;
2131
 
        box.height = thumbSize;
2132
 
 
2133
 
        XUnionRectWithRegion (&box, slot->region, slot->region);
 
1678
    GroupSelection *group;
 
1679
    XRectangle     box;
 
1680
    int            space, thumbSize;
 
1681
 
 
1682
    GROUP_WINDOW (slot->window);
 
1683
    group = gw->group;
 
1684
 
 
1685
    if (!HAS_TOP_WIN (group) || !group->tabBar)
 
1686
        return;
 
1687
 
 
1688
    space = groupGetThumbSpace (slot->window->screen);
 
1689
    thumbSize = groupGetThumbSize (slot->window->screen);
 
1690
 
 
1691
    EMPTY_REGION (slot->region);
 
1692
 
 
1693
    box.x = space + ((thumbSize + space) * slotPos);
 
1694
    box.y = space;
 
1695
 
 
1696
    box.width = thumbSize;
 
1697
    box.height = thumbSize;
 
1698
 
 
1699
    XUnionRectWithRegion (&box, slot->region, slot->region);
2134
1700
}
2135
1701
 
2136
1702
/*
2138
1704
 *
2139
1705
 */
2140
1706
void
2141
 
groupRecalcTabBarPos(GroupSelection *group, int middleX, int minX1, int maxX2)
 
1707
groupRecalcTabBarPos (GroupSelection *group,
 
1708
                      int            middleX,
 
1709
                      int            minX1,
 
1710
                      int            maxX2)
2142
1711
{
2143
 
        GroupTabBarSlot *slot;
2144
 
        GroupTabBar     *bar;
2145
 
        CompWindow      *topTab;
2146
 
        Bool            isDraggedSlotGroup = FALSE;
2147
 
        int             space, barWidth;
2148
 
        int             thumbSize;
2149
 
        int             tabsWidth = 0, tabsHeight = 0;
2150
 
        int             currentSlot;
2151
 
        XRectangle      box;
2152
 
 
2153
 
        if (!HAS_TOP_WIN (group) || !group->tabBar)
2154
 
                return;
2155
 
 
2156
 
        GROUP_SCREEN (group->screen);
2157
 
 
2158
 
        bar = group->tabBar;
2159
 
        topTab = TOP_TAB (group);
2160
 
        space = groupGetThumbSpace (group->screen);
2161
 
 
2162
 
        /* calculate the space which the tabs need */
2163
 
        for (slot = bar->slots; slot; slot = slot->next)
2164
 
        {
2165
 
                if (slot == gs->draggedSlot && gs->dragged)
2166
 
                {
2167
 
                        isDraggedSlotGroup = TRUE;
2168
 
                        continue;
2169
 
                }
2170
 
 
2171
 
                tabsWidth += (slot->region->extents.x2 - slot->region->extents.x1);
2172
 
                if ((slot->region->extents.y2 - slot->region->extents.y1) > tabsHeight)
2173
 
                        tabsHeight = slot->region->extents.y2 - slot->region->extents.y1;
2174
 
        }
2175
 
 
2176
 
        /* just a little work-a-round for first call */
2177
 
        thumbSize = groupGetThumbSize (group->screen);
2178
 
        if (bar->nSlots && tabsWidth <= 0)
2179
 
        {
2180
 
                /* first call */
2181
 
                tabsWidth = thumbSize * bar->nSlots;
2182
 
 
2183
 
                if (bar->nSlots && tabsHeight < thumbSize)
2184
 
                {
2185
 
                        /* we need to do the standard height too */
2186
 
                        tabsHeight = thumbSize;
2187
 
                }
2188
 
 
2189
 
                if (isDraggedSlotGroup)
2190
 
                        tabsWidth -= thumbSize;
2191
 
        }
2192
 
 
2193
 
        barWidth = space * (bar->nSlots + 1) + tabsWidth;
 
1712
    GroupTabBarSlot *slot;
 
1713
    GroupTabBar     *bar;
 
1714
    CompWindow      *topTab;
 
1715
    Bool            isDraggedSlotGroup = FALSE;
 
1716
    int             space, barWidth;
 
1717
    int             thumbSize;
 
1718
    int             tabsWidth = 0, tabsHeight = 0;
 
1719
    int             currentSlot;
 
1720
    XRectangle      box;
 
1721
 
 
1722
    if (!HAS_TOP_WIN (group) || !group->tabBar)
 
1723
        return;
 
1724
 
 
1725
    GROUP_SCREEN (group->screen);
 
1726
 
 
1727
    bar = group->tabBar;
 
1728
    topTab = TOP_TAB (group);
 
1729
    space = groupGetThumbSpace (group->screen);
 
1730
 
 
1731
    /* calculate the space which the tabs need */
 
1732
    for (slot = bar->slots; slot; slot = slot->next)
 
1733
    {
 
1734
        if (slot == gs->draggedSlot && gs->dragged)
 
1735
        {
 
1736
            isDraggedSlotGroup = TRUE;
 
1737
            continue;
 
1738
        }
 
1739
 
 
1740
        tabsWidth += (slot->region->extents.x2 - slot->region->extents.x1);
 
1741
        if ((slot->region->extents.y2 - slot->region->extents.y1) > tabsHeight)
 
1742
            tabsHeight = slot->region->extents.y2 - slot->region->extents.y1;
 
1743
    }
 
1744
 
 
1745
    /* just a little work-a-round for first call
 
1746
       FIXME: remove this! */
 
1747
    thumbSize = groupGetThumbSize (group->screen);
 
1748
    if (bar->nSlots && tabsWidth <= 0)
 
1749
    {
 
1750
        /* first call */
 
1751
        tabsWidth = thumbSize * bar->nSlots;
 
1752
 
 
1753
        if (bar->nSlots && tabsHeight < thumbSize)
 
1754
        {
 
1755
            /* we need to do the standard height too */
 
1756
            tabsHeight = thumbSize;
 
1757
        }
2194
1758
 
2195
1759
        if (isDraggedSlotGroup)
2196
 
        {
2197
 
                /* 1 tab is missing, so we have 1 less border */
2198
 
                barWidth -= space;
2199
 
        }
2200
 
 
2201
 
        if (maxX2 - minX1 < barWidth)
2202
 
                box.x = (maxX2 + minX1) / 2 - barWidth / 2;
2203
 
        else if (middleX - barWidth / 2 < minX1)
2204
 
                box.x = minX1;
2205
 
        else if (middleX + barWidth / 2 > maxX2)
2206
 
                box.x = maxX2 - barWidth;
2207
 
        else
2208
 
                box.x = middleX - barWidth / 2;
2209
 
 
2210
 
        box.y = WIN_Y (topTab);
2211
 
        box.width = barWidth;
2212
 
        box.height = space * 2 + tabsHeight;
2213
 
 
2214
 
        groupResizeTabBarRegion (group, &box, TRUE);
2215
 
 
2216
 
        /* recalc every slot region */
2217
 
        currentSlot = 0;
2218
 
        for (slot = bar->slots; slot; slot = slot->next)
2219
 
        {
2220
 
                if (slot == gs->draggedSlot && gs->dragged)
2221
 
                        continue;
2222
 
 
2223
 
                groupRecalcSlotPos (slot, currentSlot);
2224
 
                XOffsetRegion (slot->region,
2225
 
                                           bar->region->extents.x1,
2226
 
                                           bar->region->extents.y1);
2227
 
 
2228
 
                slot->springX = (slot->region->extents.x1 +
2229
 
                                                 slot->region->extents.x2) / 2;
2230
 
                slot->speed = 0;
2231
 
                slot->msSinceLastMove = 0;
2232
 
 
2233
 
                currentSlot++;
2234
 
        }
2235
 
 
2236
 
        bar->leftSpringX = box.x;
2237
 
        bar->rightSpringX = box.x + box.width;
2238
 
 
2239
 
        bar->rightSpeed = 0;
2240
 
        bar->leftSpeed = 0;
2241
 
 
2242
 
        bar->rightMsSinceLastMove = 0;
2243
 
        bar->leftMsSinceLastMove = 0;
 
1760
            tabsWidth -= thumbSize;
 
1761
    }
 
1762
 
 
1763
    barWidth = space * (bar->nSlots + 1) + tabsWidth;
 
1764
 
 
1765
    if (isDraggedSlotGroup)
 
1766
    {
 
1767
        /* 1 tab is missing, so we have 1 less border */
 
1768
        barWidth -= space;
 
1769
    }
 
1770
 
 
1771
    if (maxX2 - minX1 < barWidth)
 
1772
        box.x = (maxX2 + minX1) / 2 - barWidth / 2;
 
1773
    else if (middleX - barWidth / 2 < minX1)
 
1774
        box.x = minX1;
 
1775
    else if (middleX + barWidth / 2 > maxX2)
 
1776
        box.x = maxX2 - barWidth;
 
1777
    else
 
1778
        box.x = middleX - barWidth / 2;
 
1779
 
 
1780
    box.y = WIN_Y (topTab);
 
1781
    box.width = barWidth;
 
1782
    box.height = space * 2 + tabsHeight;
 
1783
 
 
1784
    groupResizeTabBarRegion (group, &box, TRUE);
 
1785
 
 
1786
    /* recalc every slot region */
 
1787
    currentSlot = 0;
 
1788
    for (slot = bar->slots; slot; slot = slot->next)
 
1789
    {
 
1790
        if (slot == gs->draggedSlot && gs->dragged)
 
1791
            continue;
 
1792
 
 
1793
        groupRecalcSlotPos (slot, currentSlot);
 
1794
        XOffsetRegion (slot->region,
 
1795
                       bar->region->extents.x1,
 
1796
                       bar->region->extents.y1);
 
1797
 
 
1798
        slot->springX = (slot->region->extents.x1 +
 
1799
                         slot->region->extents.x2) / 2;
 
1800
        slot->speed = 0;
 
1801
        slot->msSinceLastMove = 0;
 
1802
 
 
1803
        currentSlot++;
 
1804
    }
 
1805
 
 
1806
    bar->leftSpringX = box.x;
 
1807
    bar->rightSpringX = box.x + box.width;
 
1808
 
 
1809
    bar->rightSpeed = 0;
 
1810
    bar->leftSpeed = 0;
 
1811
 
 
1812
    bar->rightMsSinceLastMove = 0;
 
1813
    bar->leftMsSinceLastMove = 0;
2244
1814
}
2245
1815
 
2246
1816
void
2247
1817
groupDamageTabBarRegion (GroupSelection *group)
2248
1818
{
2249
 
        REGION reg;
2250
 
 
2251
 
        reg.rects = &reg.extents;
2252
 
        reg.numRects = 1;
2253
 
 
2254
 
        /* we use 15 pixels as damage buffer here, as there is a 10 pixel wide
2255
 
        border around the selected slot which also needs to be damaged 
2256
 
        properly - however the best way would be if slot->region was 
2257
 
        sized including the border */
 
1819
    REGION reg;
 
1820
 
 
1821
    reg.rects = &reg.extents;
 
1822
    reg.numRects = 1;
 
1823
 
 
1824
    /* we use 15 pixels as damage buffer here, as there is a 10 pixel wide
 
1825
       border around the selected slot which also needs to be damaged
 
1826
       properly - however the best way would be if slot->region was
 
1827
       sized including the border */
2258
1828
 
2259
1829
#define DAMAGE_BUFFER 20
2260
1830
 
2261
 
        reg.extents = group->tabBar->region->extents;
 
1831
    reg.extents = group->tabBar->region->extents;
2262
1832
 
2263
 
        if (group->tabBar->slots)
2264
 
        {
2265
 
                reg.extents.x1 = MIN (reg.extents.x1,
2266
 
                                                          group->tabBar->slots->region->extents.x1);
2267
 
                reg.extents.y1 = MIN (reg.extents.y1,
2268
 
                                                          group->tabBar->slots->region->extents.y1);
2269
 
                reg.extents.x2 = MAX (reg.extents.x2,
2270
 
                                                          group->tabBar->revSlots->region->extents.x2);
2271
 
                reg.extents.y2 = MAX (reg.extents.y2,
2272
 
                                                          group->tabBar->revSlots->region->extents.y2);
2273
 
        }
 
1833
    if (group->tabBar->slots)
 
1834
    {
 
1835
        reg.extents.x1 = MIN (reg.extents.x1,
 
1836
                              group->tabBar->slots->region->extents.x1);
 
1837
        reg.extents.y1 = MIN (reg.extents.y1,
 
1838
                              group->tabBar->slots->region->extents.y1);
 
1839
        reg.extents.x2 = MAX (reg.extents.x2,
 
1840
                              group->tabBar->revSlots->region->extents.x2);
 
1841
        reg.extents.y2 = MAX (reg.extents.y2,
 
1842
                              group->tabBar->revSlots->region->extents.y2);
 
1843
    }
2274
1844
 
2275
1845
    reg.extents.x1 -= DAMAGE_BUFFER;
2276
1846
    reg.extents.y1 -= DAMAGE_BUFFER;
2277
1847
    reg.extents.x2 += DAMAGE_BUFFER;
2278
1848
    reg.extents.y2 += DAMAGE_BUFFER;
2279
1849
 
2280
 
        damageScreenRegion (group->screen, &reg);
 
1850
    damageScreenRegion (group->screen, &reg);
2281
1851
}
2282
1852
 
2283
1853
void
2284
1854
groupMoveTabBarRegion (GroupSelection *group,
2285
 
                                           int            dx,
2286
 
                                           int            dy,
2287
 
                                           Bool           syncIPW)
 
1855
                       int            dx,
 
1856
                       int            dy,
 
1857
                       Bool           syncIPW)
2288
1858
{
2289
 
        groupDamageTabBarRegion (group);
2290
 
 
2291
 
        XOffsetRegion (group->tabBar->region, dx, dy);
2292
 
 
2293
 
        if (syncIPW)
2294
 
                XMoveWindow (group->screen->display->display,
2295
 
                                         group->inputPrevention,
2296
 
                                         group->tabBar->leftSpringX,
2297
 
                                         group->tabBar->region->extents.y1);
2298
 
 
2299
 
        groupDamageTabBarRegion (group);
 
1859
    groupDamageTabBarRegion (group);
 
1860
 
 
1861
    XOffsetRegion (group->tabBar->region, dx, dy);
 
1862
 
 
1863
    if (syncIPW)
 
1864
        XMoveWindow (group->screen->display->display,
 
1865
                     group->inputPrevention,
 
1866
                     group->tabBar->leftSpringX,
 
1867
                     group->tabBar->region->extents.y1);
 
1868
 
 
1869
    groupDamageTabBarRegion (group);
2300
1870
}
2301
1871
 
2302
1872
void
2303
1873
groupResizeTabBarRegion (GroupSelection *group,
2304
 
                                                 XRectangle     *box,
2305
 
                                                 Bool           syncIPW)
 
1874
                         XRectangle     *box,
 
1875
                         Bool           syncIPW)
2306
1876
{
2307
 
        int oldWidth;
2308
 
 
2309
 
        groupDamageTabBarRegion (group);
2310
 
 
2311
 
        oldWidth = group->tabBar->region->extents.x2 -
2312
 
                       group->tabBar->region->extents.x1;
2313
 
 
2314
 
        if (group->tabBar->bgLayer && oldWidth != box->width && syncIPW)
2315
 
        {
2316
 
                group->tabBar->bgLayer =
2317
 
                        groupRebuildCairoLayer (group->screen,
2318
 
                                                                        group->tabBar->bgLayer,
2319
 
                                                                        box->width +
2320
 
                                                                        groupGetThumbSpace (group->screen) +
2321
 
                                                                        groupGetThumbSize (group->screen),
2322
 
                                                                        box->height);
2323
 
                groupRenderTabBarBackground (group);
2324
 
 
2325
 
                /* invalidate old width */
2326
 
                group->tabBar->oldWidth = 0;
2327
 
        }
2328
 
 
2329
 
        EMPTY_REGION (group->tabBar->region);
2330
 
        XUnionRectWithRegion (box, group->tabBar->region, group->tabBar->region);
2331
 
 
2332
 
        if (syncIPW)
2333
 
        {
2334
 
                XWindowChanges xwc;
2335
 
 
2336
 
                xwc.x = box->x;
2337
 
                xwc.y = box->y;
2338
 
                xwc.width = box->width;
2339
 
                xwc.height = box->height;
2340
 
 
2341
 
                xwc.stack_mode = Above;
2342
 
                xwc.sibling = HAS_TOP_WIN (group) ? TOP_TAB (group)->id : None;
2343
 
 
2344
 
                XConfigureWindow (group->screen->display->display,
2345
 
                                                  group->inputPrevention,
2346
 
                                                  CWSibling | CWStackMode | CWX | CWY |
2347
 
                                                  CWWidth | CWHeight,
2348
 
                                                  &xwc);
2349
 
        }
2350
 
 
2351
 
        groupDamageTabBarRegion (group);
 
1877
    int oldWidth;
 
1878
 
 
1879
    groupDamageTabBarRegion (group);
 
1880
 
 
1881
    oldWidth = group->tabBar->region->extents.x2 -
 
1882
        group->tabBar->region->extents.x1;
 
1883
 
 
1884
    if (group->tabBar->bgLayer && oldWidth != box->width && syncIPW)
 
1885
    {
 
1886
        group->tabBar->bgLayer =
 
1887
            groupRebuildCairoLayer (group->screen,
 
1888
                                    group->tabBar->bgLayer,
 
1889
                                    box->width +
 
1890
                                    groupGetThumbSpace (group->screen) +
 
1891
                                    groupGetThumbSize (group->screen),
 
1892
                                    box->height);
 
1893
        groupRenderTabBarBackground (group);
 
1894
 
 
1895
        /* invalidate old width */
 
1896
        group->tabBar->oldWidth = 0;
 
1897
    }
 
1898
 
 
1899
    EMPTY_REGION (group->tabBar->region);
 
1900
    XUnionRectWithRegion (box, group->tabBar->region, group->tabBar->region);
 
1901
 
 
1902
    if (syncIPW)
 
1903
    {
 
1904
        XWindowChanges xwc;
 
1905
 
 
1906
        xwc.x = box->x;
 
1907
        xwc.y = box->y;
 
1908
        xwc.width = box->width;
 
1909
        xwc.height = box->height;
 
1910
 
 
1911
        xwc.stack_mode = Above;
 
1912
        xwc.sibling = HAS_TOP_WIN (group) ? TOP_TAB (group)->id : None;
 
1913
 
 
1914
        XConfigureWindow (group->screen->display->display,
 
1915
                          group->inputPrevention,
 
1916
                          CWSibling | CWStackMode | CWX | CWY |
 
1917
                          CWWidth | CWHeight,
 
1918
                          &xwc);
 
1919
    }
 
1920
 
 
1921
    groupDamageTabBarRegion (group);
2352
1922
}
2353
1923
 
2354
1924
/*
2357
1927
 */
2358
1928
void
2359
1929
groupInsertTabBarSlotBefore (GroupTabBar     *bar,
2360
 
                                                         GroupTabBarSlot *slot,
2361
 
                                                         GroupTabBarSlot *nextSlot)
 
1930
                             GroupTabBarSlot *slot,
 
1931
                             GroupTabBarSlot *nextSlot)
2362
1932
{
2363
 
        GroupTabBarSlot *prev = nextSlot->prev;
2364
 
        CompWindow      *w = slot->window;
2365
 
 
2366
 
        GROUP_WINDOW (w);
2367
 
 
2368
 
        if (prev)
2369
 
        {
2370
 
                slot->prev = prev;
2371
 
                prev->next = slot;
2372
 
        }
2373
 
        else
2374
 
        {
2375
 
                bar->slots = slot;
2376
 
                slot->prev = NULL;
2377
 
        }
2378
 
 
2379
 
        slot->next = nextSlot;
2380
 
        nextSlot->prev = slot;
2381
 
        bar->nSlots++;
2382
 
 
2383
 
        /* Moving bar->region->extents.x1 / x2 as minX1 / maxX2 will work,
2384
 
           because the tab-bar got wider now, so it will put it in
2385
 
           the average between them, which is
2386
 
           (bar->region->extents.x1 + bar->region->extents.x2) / 2 anyway. */
2387
 
        groupRecalcTabBarPos (gw->group,
2388
 
                                                  (bar->region->extents.x1 +
2389
 
                                                   bar->region->extents.x2) / 2,
2390
 
                                                  bar->region->extents.x1, bar->region->extents.x2);
 
1933
    GroupTabBarSlot *prev = nextSlot->prev;
 
1934
    CompWindow      *w = slot->window;
 
1935
 
 
1936
    GROUP_WINDOW (w);
 
1937
 
 
1938
    if (prev)
 
1939
    {
 
1940
        slot->prev = prev;
 
1941
        prev->next = slot;
 
1942
    }
 
1943
    else
 
1944
    {
 
1945
        bar->slots = slot;
 
1946
        slot->prev = NULL;
 
1947
    }
 
1948
 
 
1949
    slot->next = nextSlot;
 
1950
    nextSlot->prev = slot;
 
1951
    bar->nSlots++;
 
1952
 
 
1953
    /* Moving bar->region->extents.x1 / x2 as minX1 / maxX2 will work,
 
1954
       because the tab-bar got wider now, so it will put it in
 
1955
       the average between them, which is
 
1956
       (bar->region->extents.x1 + bar->region->extents.x2) / 2 anyway. */
 
1957
    groupRecalcTabBarPos (gw->group,
 
1958
                          (bar->region->extents.x1 +
 
1959
                           bar->region->extents.x2) / 2,
 
1960
                          bar->region->extents.x1, bar->region->extents.x2);
2391
1961
}
2392
1962
 
2393
1963
/*
2396
1966
 */
2397
1967
void
2398
1968
groupInsertTabBarSlotAfter (GroupTabBar     *bar,
2399
 
                                                        GroupTabBarSlot *slot,
2400
 
                                                        GroupTabBarSlot *prevSlot)
 
1969
                            GroupTabBarSlot *slot,
 
1970
                            GroupTabBarSlot *prevSlot)
2401
1971
{
2402
 
        GroupTabBarSlot *next = prevSlot->next;
2403
 
        CompWindow      *w = slot->window;
2404
 
 
2405
 
        GROUP_WINDOW (w);
2406
 
 
2407
 
        if (next)
2408
 
        {
2409
 
                slot->next = next;
2410
 
                next->prev = slot;
2411
 
        }
2412
 
        else
2413
 
        {
2414
 
                bar->revSlots = slot;
2415
 
                slot->next = NULL;
2416
 
        }
2417
 
 
2418
 
        slot->prev = prevSlot;
2419
 
        prevSlot->next = slot;
2420
 
        bar->nSlots++;
2421
 
 
2422
 
        /* Moving bar->region->extents.x1 / x2 as minX1 / maxX2 will work,
2423
 
           because the tab-bar got wider now, so it will put it in the
2424
 
           average between them, which is
2425
 
           (bar->region->extents.x1 + bar->region->extents.x2) / 2 anyway. */
2426
 
        groupRecalcTabBarPos (gw->group,
2427
 
                                                  (bar->region->extents.x1 +
2428
 
                                                   bar->region->extents.x2) / 2,
2429
 
                                                  bar->region->extents.x1, bar->region->extents.x2);
 
1972
    GroupTabBarSlot *next = prevSlot->next;
 
1973
    CompWindow      *w = slot->window;
 
1974
 
 
1975
    GROUP_WINDOW (w);
 
1976
 
 
1977
    if (next)
 
1978
    {
 
1979
        slot->next = next;
 
1980
        next->prev = slot;
 
1981
    }
 
1982
    else
 
1983
    {
 
1984
        bar->revSlots = slot;
 
1985
        slot->next = NULL;
 
1986
    }
 
1987
 
 
1988
    slot->prev = prevSlot;
 
1989
    prevSlot->next = slot;
 
1990
    bar->nSlots++;
 
1991
 
 
1992
    /* Moving bar->region->extents.x1 / x2 as minX1 / maxX2 will work,
 
1993
       because the tab-bar got wider now, so it will put it in the
 
1994
       average between them, which is
 
1995
       (bar->region->extents.x1 + bar->region->extents.x2) / 2 anyway. */
 
1996
    groupRecalcTabBarPos (gw->group,
 
1997
                          (bar->region->extents.x1 +
 
1998
                           bar->region->extents.x2) / 2,
 
1999
                          bar->region->extents.x1, bar->region->extents.x2);
2430
2000
}
2431
2001
 
2432
2002
/*
2435
2005
 */
2436
2006
void
2437
2007
groupInsertTabBarSlot (GroupTabBar     *bar,
2438
 
                                           GroupTabBarSlot *slot)
 
2008
                       GroupTabBarSlot *slot)
2439
2009
{
2440
 
        CompWindow *w = slot->window;
2441
 
 
2442
 
        GROUP_WINDOW (w);
2443
 
        
2444
 
        if (bar->slots)
2445
 
        {
2446
 
                bar->revSlots->next = slot;
2447
 
                slot->prev = bar->revSlots;
2448
 
                slot->next = NULL;
2449
 
        }
2450
 
        else
2451
 
        {
2452
 
                slot->prev = NULL;
2453
 
                slot->next = NULL;
2454
 
                bar->slots = slot;
2455
 
        }
2456
 
 
2457
 
        bar->revSlots = slot;
2458
 
        bar->nSlots++;
2459
 
 
2460
 
        /* Moving bar->region->extents.x1 / x2 as minX1 / maxX2 will work,
2461
 
           because the tab-bar got wider now, so it will put it in
2462
 
           the average between them, which is
2463
 
           (bar->region->extents.x1 + bar->region->extents.x2) / 2 anyway. */
2464
 
        groupRecalcTabBarPos (gw->group,
2465
 
                                                  (bar->region->extents.x1 +
2466
 
                                                   bar->region->extents.x2) / 2,
2467
 
                                                  bar->region->extents.x1, bar->region->extents.x2);
 
2010
    CompWindow *w = slot->window;
 
2011
 
 
2012
    GROUP_WINDOW (w);
 
2013
 
 
2014
    if (bar->slots)
 
2015
    {
 
2016
        bar->revSlots->next = slot;
 
2017
        slot->prev = bar->revSlots;
 
2018
        slot->next = NULL;
 
2019
    }
 
2020
    else
 
2021
    {
 
2022
        slot->prev = NULL;
 
2023
        slot->next = NULL;
 
2024
        bar->slots = slot;
 
2025
    }
 
2026
 
 
2027
    bar->revSlots = slot;
 
2028
    bar->nSlots++;
 
2029
 
 
2030
    /* Moving bar->region->extents.x1 / x2 as minX1 / maxX2 will work,
 
2031
       because the tab-bar got wider now, so it will put it in
 
2032
       the average between them, which is
 
2033
       (bar->region->extents.x1 + bar->region->extents.x2) / 2 anyway. */
 
2034
    groupRecalcTabBarPos (gw->group,
 
2035
                          (bar->region->extents.x1 +
 
2036
                           bar->region->extents.x2) / 2,
 
2037
                          bar->region->extents.x1, bar->region->extents.x2);
2468
2038
}
2469
2039
 
2470
2040
/*
2473
2043
 */
2474
2044
void
2475
2045
groupUnhookTabBarSlot (GroupTabBar     *bar,
2476
 
                                           GroupTabBarSlot *slot,
2477
 
                                           Bool            temporary)
 
2046
                       GroupTabBarSlot *slot,
 
2047
                       Bool            temporary)
2478
2048
{
2479
 
        GroupTabBarSlot *prev = slot->prev;
2480
 
        GroupTabBarSlot *next = slot->next;
2481
 
        CompWindow      *w = slot->window;
2482
 
 
2483
 
        GROUP_WINDOW (w);
2484
 
 
2485
 
        if (prev)
2486
 
                prev->next = next;
2487
 
        else
2488
 
                bar->slots = next;
2489
 
 
2490
 
        if (next)
2491
 
                next->prev = prev;
2492
 
        else
2493
 
                bar->revSlots = prev;
2494
 
 
2495
 
        slot->prev = NULL;
2496
 
        slot->next = NULL;
2497
 
        bar->nSlots--;
2498
 
 
2499
 
        if (IS_TOP_TAB (w, gw->group) && !temporary)
2500
 
        {
2501
 
                if (next)
2502
 
                        groupChangeTab (next, RotateRight);
2503
 
                else if (prev)
2504
 
                        groupChangeTab (prev, RotateLeft);
2505
 
                else if (gw->group->nWins == 1)
2506
 
                        gw->group->topTab = NULL;
2507
 
 
2508
 
                if (groupGetUntabOnClose (w->screen))
2509
 
                        groupUntabGroup (gw->group);
2510
 
        }
2511
 
 
2512
 
        if (IS_PREV_TOP_TAB (w, gw->group) && !temporary)
2513
 
                gw->group->prevTopTab = NULL;
2514
 
 
2515
 
        if (slot == bar->hoveredSlot)
2516
 
                bar->hoveredSlot = NULL;
2517
 
 
2518
 
        if (slot == bar->textSlot)
2519
 
        {
2520
 
                bar->textSlot = NULL;
2521
 
 
2522
 
                if (bar->textLayer)
2523
 
                {
2524
 
                        if (bar->textLayer->state == PaintFadeIn ||
2525
 
                                bar->textLayer->state == PaintOn)
2526
 
                        {
2527
 
                                bar->textLayer->animationTime =
2528
 
                                        (groupGetFadeTextTime (w->screen) * 1000) -
2529
 
                                        bar->textLayer->animationTime;
2530
 
                                bar->textLayer->state = PaintFadeOut;
2531
 
                        }
2532
 
                }
2533
 
        }
2534
 
 
2535
 
        /* Moving bar->region->extents.x1 / x2 as minX1 / maxX2 will work,
2536
 
           because the tab-bar got thiner now, so
2537
 
           (bar->region->extents.x1 + bar->region->extents.x2) / 2
2538
 
           Won't cause the new x1 / x2 to be outside the original region. */
2539
 
        groupRecalcTabBarPos (gw->group,
2540
 
                                                  (bar->region->extents.x1 +
2541
 
                                                   bar->region->extents.x2) / 2,
2542
 
                                                  bar->region->extents.x1, bar->region->extents.x2);
 
2049
    GroupTabBarSlot *tempSlot;
 
2050
    GroupTabBarSlot *prev = slot->prev;
 
2051
    GroupTabBarSlot *next = slot->next;
 
2052
    CompWindow      *w = slot->window;
 
2053
    CompScreen      *s = w->screen;
 
2054
    GroupSelection  *group;
 
2055
 
 
2056
    GROUP_WINDOW (w);
 
2057
 
 
2058
    group = gw->group;
 
2059
 
 
2060
    /* check if slot is not already unhooked */
 
2061
    for (tempSlot = bar->slots; tempSlot; tempSlot = tempSlot->next)
 
2062
        if (tempSlot == slot)
 
2063
            break;
 
2064
 
 
2065
    if (!tempSlot)
 
2066
        return;
 
2067
 
 
2068
    if (prev)
 
2069
        prev->next = next;
 
2070
    else
 
2071
        bar->slots = next;
 
2072
 
 
2073
    if (next)
 
2074
        next->prev = prev;
 
2075
    else
 
2076
        bar->revSlots = prev;
 
2077
 
 
2078
    slot->prev = NULL;
 
2079
    slot->next = NULL;
 
2080
    bar->nSlots--;
 
2081
 
 
2082
    if (!temporary)
 
2083
    {
 
2084
        if (IS_PREV_TOP_TAB (w, group))
 
2085
            group->prevTopTab = NULL;
 
2086
        if (IS_TOP_TAB (w, group))
 
2087
        {
 
2088
            group->topTab = NULL;
 
2089
 
 
2090
            if (next)
 
2091
                groupChangeTab (next, RotateRight);
 
2092
            else if (prev)
 
2093
                groupChangeTab (prev, RotateLeft);
 
2094
 
 
2095
            if (groupGetUntabOnClose (s))
 
2096
                groupUntabGroup (group);
 
2097
        }
 
2098
    }
 
2099
 
 
2100
    if (slot == bar->hoveredSlot)
 
2101
        bar->hoveredSlot = NULL;
 
2102
 
 
2103
    if (slot == bar->textSlot)
 
2104
    {
 
2105
        bar->textSlot = NULL;
 
2106
 
 
2107
        if (bar->textLayer)
 
2108
        {
 
2109
            if (bar->textLayer->state == PaintFadeIn ||
 
2110
                bar->textLayer->state == PaintOn)
 
2111
            {
 
2112
                bar->textLayer->animationTime =
 
2113
                    (groupGetFadeTextTime (s) * 1000) -
 
2114
                    bar->textLayer->animationTime;
 
2115
                bar->textLayer->state = PaintFadeOut;
 
2116
            }
 
2117
        }
 
2118
    }
 
2119
 
 
2120
    /* Moving bar->region->extents.x1 / x2 as minX1 / maxX2 will work,
 
2121
       because the tab-bar got thiner now, so
 
2122
       (bar->region->extents.x1 + bar->region->extents.x2) / 2
 
2123
       Won't cause the new x1 / x2 to be outside the original region. */
 
2124
    groupRecalcTabBarPos (group,
 
2125
                          (bar->region->extents.x1 +
 
2126
                           bar->region->extents.x2) / 2,
 
2127
                          bar->region->extents.x1,
 
2128
                          bar->region->extents.x2);
2543
2129
}
2544
2130
 
2545
2131
/*
2548
2134
 */
2549
2135
void
2550
2136
groupDeleteTabBarSlot (GroupTabBar     *bar,
2551
 
                                           GroupTabBarSlot *slot)
 
2137
                       GroupTabBarSlot *slot)
2552
2138
{
2553
 
        CompWindow *w = slot->window;
2554
 
 
2555
 
        GROUP_WINDOW (w);
2556
 
        GROUP_SCREEN (w->screen);
2557
 
 
2558
 
        groupUnhookTabBarSlot (bar, slot, FALSE);
2559
 
 
2560
 
        if (slot->region)
2561
 
                XDestroyRegion (slot->region);
2562
 
 
2563
 
        if (slot == gs->draggedSlot)
2564
 
        {
2565
 
                gs->draggedSlot = NULL;
2566
 
                gs->dragged = FALSE;
2567
 
 
2568
 
                if (gs->grabState == ScreenGrabTabDrag)
2569
 
                        groupGrabScreen (w->screen, ScreenGrabNone);
2570
 
        }
2571
 
 
2572
 
        gw->slot = NULL;
2573
 
        groupUpdateWindowProperty (w);
2574
 
        free (slot);
 
2139
    CompWindow *w = slot->window;
 
2140
 
 
2141
    GROUP_WINDOW (w);
 
2142
    GROUP_SCREEN (w->screen);
 
2143
 
 
2144
    groupUnhookTabBarSlot (bar, slot, FALSE);
 
2145
 
 
2146
    if (slot->region)
 
2147
        XDestroyRegion (slot->region);
 
2148
 
 
2149
    if (slot == gs->draggedSlot)
 
2150
    {
 
2151
        gs->draggedSlot = NULL;
 
2152
        gs->dragged = FALSE;
 
2153
 
 
2154
        if (gs->grabState == ScreenGrabTabDrag)
 
2155
            groupGrabScreen (w->screen, ScreenGrabNone);
 
2156
    }
 
2157
 
 
2158
    gw->slot = NULL;
 
2159
    groupUpdateWindowProperty (w);
 
2160
    free (slot);
2575
2161
}
2576
2162
 
2577
2163
/*
2578
2164
 * groupCreateSlot
2579
2165
 *
2580
2166
 */
2581
 
void groupCreateSlot(GroupSelection *group, CompWindow *w)
 
2167
void groupCreateSlot (GroupSelection *group,
 
2168
                      CompWindow     *w)
2582
2169
{
2583
 
        GroupTabBarSlot *slot;
2584
 
 
2585
 
        GROUP_WINDOW (w);
2586
 
 
2587
 
        if (!group->tabBar)
2588
 
                return;
2589
 
 
2590
 
        slot = malloc (sizeof (GroupTabBarSlot));
2591
 
        slot->window = w;
2592
 
 
2593
 
        slot->region = XCreateRegion ();
2594
 
 
2595
 
        groupInsertTabBarSlot (group->tabBar, slot);
2596
 
        gw->slot = slot;
2597
 
        groupUpdateWindowProperty (w);
 
2170
    GroupTabBarSlot *slot;
 
2171
 
 
2172
    GROUP_WINDOW (w);
 
2173
 
 
2174
    if (!group->tabBar)
 
2175
        return;
 
2176
 
 
2177
    slot = malloc (sizeof (GroupTabBarSlot));
 
2178
    if (!slot)
 
2179
        return;
 
2180
 
 
2181
    slot->window = w;
 
2182
 
 
2183
    slot->region = XCreateRegion ();
 
2184
 
 
2185
    groupInsertTabBarSlot (group->tabBar, slot);
 
2186
    gw->slot = slot;
 
2187
    groupUpdateWindowProperty (w);
2598
2188
}
2599
2189
 
2600
 
#define SPRING_K         groupGetDragSpringK(s)
2601
 
#define FRICTION         groupGetDragFriction(s)
2602
 
#define SIZE             groupGetThumbSize(s)
2603
 
#define BORDER           groupGetBorderRadius(s)
 
2190
#define SPRING_K     groupGetDragSpringK(s)
 
2191
#define FRICTION     groupGetDragFriction(s)
 
2192
#define SIZE         groupGetThumbSize(s)
 
2193
#define BORDER       groupGetBorderRadius(s)
2604
2194
#define Y_START_MOVE groupGetDragYDistance(s)
2605
 
#define SPEED_LIMIT      groupGetDragSpeedLimit(s)
 
2195
#define SPEED_LIMIT  groupGetDragSpeedLimit(s)
2606
2196
 
2607
2197
/*
2608
2198
 * groupSpringForce
2610
2200
 */
2611
2201
static inline int
2612
2202
groupSpringForce (CompScreen *s,
2613
 
                                  int        centerX,
2614
 
                                  int        springX)
 
2203
                  int        centerX,
 
2204
                  int        springX)
2615
2205
{
2616
 
        /* Each slot has a spring attached to it, starting at springX,
2617
 
           and ending at the center of the slot (centerX).
2618
 
           The spring will cause the slot to move, using the
2619
 
           well-known physical formula F = k * dl... */
2620
 
        return -SPRING_K * (centerX - springX);
 
2206
    /* Each slot has a spring attached to it, starting at springX,
 
2207
       and ending at the center of the slot (centerX).
 
2208
       The spring will cause the slot to move, using the
 
2209
       well-known physical formula F = k * dl... */
 
2210
    return -SPRING_K * (centerX - springX);
2621
2211
}
2622
2212
 
2623
2213
/*
2626
2216
 */
2627
2217
static int
2628
2218
groupDraggedSlotForce (CompScreen *s,
2629
 
                                           int        distanceX,
2630
 
                                           int        distanceY)
 
2219
                       int        distanceX,
 
2220
                       int        distanceY)
2631
2221
{
2632
 
        /* The dragged slot will make the slot move, to get
2633
 
           DnD animations (slots will make room for the newly inserted slot).
2634
 
           As the dragged slot is closer to the slot, it will put
2635
 
           more force on the slot, causing it to make room for the dragged slot...
2636
 
           But if the dragged slot gets too close to the slot, they are
2637
 
           going to be reordered soon, so the force will get lower.
2638
 
 
2639
 
           If the dragged slot is in the other side of the slot,
2640
 
           it will have to make force in the opposite direction.
2641
 
 
2642
 
           So we the needed funtion is an odd function that goes
2643
 
           up at first, and down after that.
2644
 
           Sinus is a function like that... :)
2645
 
 
2646
 
           The maximum is got when x = (x1 + x2) / 2,
2647
 
           in this case: x = SIZE + BORDER.
2648
 
           Because of that, for x = SIZE + BORDER,
2649
 
           we get a force of SPRING_K * (SIZE + BORDER) / 2.
2650
 
           That equals to the force we get from the the spring.
2651
 
           This way, the slot won't move when its distance from
2652
 
           the dragged slot is SIZE + BORDER (which is the default
2653
 
           distance between slots).
2654
 
        */
2655
 
 
2656
 
        /* The maximum value */
2657
 
        float a = SPRING_K * (SIZE + BORDER) / 2;
2658
 
        /* This will make distanceX == 2 * (SIZE + BORDER) to get 0,
2659
 
           and distanceX == (SIZE + BORDER) to get the maximum. */
2660
 
        float b = PI /  (2 * SIZE + 2 * BORDER);
2661
 
 
2662
 
        /* If there is some distance between the slots in the y axis,
2663
 
           the slot should get less force... For this, we change max
2664
 
           to a lower value, using a simple linear function. */
2665
 
 
2666
 
        if (distanceY < Y_START_MOVE)
2667
 
                a *= 1.0f - (float)distanceY / Y_START_MOVE;
2668
 
        else
2669
 
                a = 0;
2670
 
 
2671
 
        if (abs (distanceX) < 2 * (SIZE + BORDER))
2672
 
                return a * sin (b * distanceX);
2673
 
        else
2674
 
                return 0;
 
2222
    /* The dragged slot will make the slot move, to get
 
2223
       DnD animations (slots will make room for the newly inserted slot).
 
2224
       As the dragged slot is closer to the slot, it will put
 
2225
       more force on the slot, causing it to make room for the dragged slot...
 
2226
       But if the dragged slot gets too close to the slot, they are
 
2227
       going to be reordered soon, so the force will get lower.
 
2228
 
 
2229
       If the dragged slot is in the other side of the slot,
 
2230
       it will have to make force in the opposite direction.
 
2231
 
 
2232
       So we the needed funtion is an odd function that goes
 
2233
       up at first, and down after that.
 
2234
       Sinus is a function like that... :)
 
2235
 
 
2236
       The maximum is got when x = (x1 + x2) / 2,
 
2237
       in this case: x = SIZE + BORDER.
 
2238
       Because of that, for x = SIZE + BORDER,
 
2239
       we get a force of SPRING_K * (SIZE + BORDER) / 2.
 
2240
       That equals to the force we get from the the spring.
 
2241
       This way, the slot won't move when its distance from
 
2242
       the dragged slot is SIZE + BORDER (which is the default
 
2243
       distance between slots).
 
2244
       */
 
2245
 
 
2246
    /* The maximum value */
 
2247
    float a = SPRING_K * (SIZE + BORDER) / 2;
 
2248
    /* This will make distanceX == 2 * (SIZE + BORDER) to get 0,
 
2249
       and distanceX == (SIZE + BORDER) to get the maximum. */
 
2250
    float b = PI /  (2 * SIZE + 2 * BORDER);
 
2251
 
 
2252
    /* If there is some distance between the slots in the y axis,
 
2253
       the slot should get less force... For this, we change max
 
2254
       to a lower value, using a simple linear function. */
 
2255
 
 
2256
    if (distanceY < Y_START_MOVE)
 
2257
        a *= 1.0f - (float)distanceY / Y_START_MOVE;
 
2258
    else
 
2259
        a = 0;
 
2260
 
 
2261
    if (abs (distanceX) < 2 * (SIZE + BORDER))
 
2262
        return a * sin (b * distanceX);
 
2263
    else
 
2264
        return 0;
2675
2265
}
2676
2266
 
2677
2267
/*
2680
2270
 */
2681
2271
static inline void
2682
2272
groupApplyFriction (CompScreen *s,
2683
 
                                        int        *speed)
 
2273
                    int        *speed)
2684
2274
{
2685
 
        if (abs (*speed) < FRICTION)
2686
 
                *speed = 0;
2687
 
        else if (*speed > 0)
2688
 
                *speed -= FRICTION;
2689
 
        else if (*speed < 0)
2690
 
                *speed += FRICTION;
 
2275
    if (abs (*speed) < FRICTION)
 
2276
        *speed = 0;
 
2277
    else if (*speed > 0)
 
2278
        *speed -= FRICTION;
 
2279
    else if (*speed < 0)
 
2280
        *speed += FRICTION;
2691
2281
}
2692
2282
 
2693
2283
/*
2696
2286
 */
2697
2287
static inline void
2698
2288
groupApplySpeedLimit (CompScreen *s,
2699
 
                                          int        *speed)
 
2289
                      int        *speed)
2700
2290
{
2701
 
        if (*speed > SPEED_LIMIT)
2702
 
                *speed = SPEED_LIMIT;
2703
 
        else if (*speed < -SPEED_LIMIT)
2704
 
                *speed = -SPEED_LIMIT;
 
2291
    if (*speed > SPEED_LIMIT)
 
2292
        *speed = SPEED_LIMIT;
 
2293
    else if (*speed < -SPEED_LIMIT)
 
2294
        *speed = -SPEED_LIMIT;
2705
2295
}
2706
2296
 
2707
2297
/*
2710
2300
 */
2711
2301
void
2712
2302
groupApplyForces (CompScreen      *s,
2713
 
                                  GroupTabBar     *bar,
2714
 
                                  GroupTabBarSlot *draggedSlot)
 
2303
                  GroupTabBar     *bar,
 
2304
                  GroupTabBarSlot *draggedSlot)
2715
2305
{
2716
 
        GroupTabBarSlot *slot, *slot2;
2717
 
        int             centerX, centerY;
2718
 
        int             draggedCenterX, draggedCenterY;
2719
 
 
2720
 
        if (draggedSlot)
2721
 
        {
2722
 
                int vx, vy;
2723
 
 
2724
 
                groupGetDrawOffsetForSlot (draggedSlot, &vx, &vy);
2725
 
 
2726
 
                draggedCenterX = ((draggedSlot->region->extents.x1 +
2727
 
                                                   draggedSlot->region->extents.x2) / 2) + vx;
2728
 
                draggedCenterY = ((draggedSlot->region->extents.y1 +
2729
 
                                                   draggedSlot->region->extents.y2) / 2) + vy;
2730
 
        }
2731
 
        else
2732
 
        {
2733
 
                draggedCenterX = 0;
2734
 
                draggedCenterY = 0;
2735
 
        }
2736
 
 
2737
 
        bar->leftSpeed += groupSpringForce(s,
2738
 
                                                                           bar->region->extents.x1,
2739
 
                                                                           bar->leftSpringX);
2740
 
        bar->rightSpeed += groupSpringForce(s,
2741
 
                                                                                bar->region->extents.x2,
2742
 
                                                                                bar->rightSpringX);
2743
 
 
2744
 
        if (draggedSlot)
2745
 
        {
2746
 
                int leftForce, rightForce;
2747
 
 
2748
 
                leftForce = groupDraggedSlotForce(s,
2749
 
                                                                                  bar->region->extents.x1 -
2750
 
                                                                                  SIZE / 2 - draggedCenterX,
2751
 
                                                                                  abs ((bar->region->extents.y1 +
2752
 
                                                                                                bar->region->extents.y2) / 2 -
2753
 
                                                                                           draggedCenterY));
2754
 
 
2755
 
                rightForce = groupDraggedSlotForce (s,
2756
 
                                                                                        bar->region->extents.x2 +
2757
 
                                                                                        SIZE / 2 - draggedCenterX,
2758
 
                                                                                        abs ((bar->region->extents.y1 +
2759
 
                                                                                                  bar->region->extents.y2) / 2 -
2760
 
                                                                                                 draggedCenterY));
2761
 
 
2762
 
                if (leftForce < 0)
2763
 
                        bar->leftSpeed += leftForce;
2764
 
                if (rightForce > 0)
2765
 
                        bar->rightSpeed += rightForce;
2766
 
        }
2767
 
 
2768
 
        for (slot = bar->slots; slot; slot = slot->next)
2769
 
        {
2770
 
                centerX = (slot->region->extents.x1 + slot->region->extents.x2) / 2;
2771
 
                centerY = (slot->region->extents.y1 + slot->region->extents.y2) / 2;
2772
 
 
2773
 
                slot->speed += groupSpringForce (s, centerX, slot->springX);
2774
 
 
2775
 
                if (draggedSlot && draggedSlot != slot)
2776
 
                {
2777
 
                        int draggedSlotForce;
2778
 
                        draggedSlotForce =
2779
 
                                groupDraggedSlotForce(s, centerX - draggedCenterX,
2780
 
                                                                          abs (centerY - draggedCenterY));
2781
 
 
2782
 
                        slot->speed += draggedSlotForce;
2783
 
                        slot2 = NULL;
2784
 
 
2785
 
                        if (draggedSlotForce < 0)
2786
 
                        {
2787
 
                                slot2 = slot->prev;
2788
 
                                bar->leftSpeed += draggedSlotForce;
2789
 
                        }
2790
 
                        else if (draggedSlotForce > 0)
2791
 
                        {
2792
 
                                slot2 = slot->next;
2793
 
                                bar->rightSpeed += draggedSlotForce;
2794
 
                        }
2795
 
 
2796
 
                        while (slot2)
2797
 
                        {
2798
 
                                if (slot2 != draggedSlot)
2799
 
                                        slot2->speed += draggedSlotForce;
2800
 
 
2801
 
                                slot2 = (draggedSlotForce < 0) ? slot2->prev : slot2->next;
2802
 
                        }
2803
 
                }
2804
 
        }
2805
 
 
2806
 
        for (slot = bar->slots; slot; slot = slot->next)
2807
 
        {
2808
 
                groupApplyFriction (s, &slot->speed);
2809
 
                groupApplySpeedLimit (s, &slot->speed);
2810
 
        }
2811
 
 
2812
 
        groupApplyFriction (s, &bar->leftSpeed);
2813
 
        groupApplySpeedLimit (s, &bar->leftSpeed);
2814
 
 
2815
 
        groupApplyFriction (s, &bar->rightSpeed);
2816
 
        groupApplySpeedLimit (s, &bar->rightSpeed);
 
2306
    GroupTabBarSlot *slot, *slot2;
 
2307
    int             centerX, centerY;
 
2308
    int             draggedCenterX, draggedCenterY;
 
2309
 
 
2310
    if (draggedSlot)
 
2311
    {
 
2312
        int vx, vy;
 
2313
 
 
2314
        groupGetDrawOffsetForSlot (draggedSlot, &vx, &vy);
 
2315
 
 
2316
        draggedCenterX = ((draggedSlot->region->extents.x1 +
 
2317
                           draggedSlot->region->extents.x2) / 2) + vx;
 
2318
        draggedCenterY = ((draggedSlot->region->extents.y1 +
 
2319
                           draggedSlot->region->extents.y2) / 2) + vy;
 
2320
    }
 
2321
    else
 
2322
    {
 
2323
        draggedCenterX = 0;
 
2324
        draggedCenterY = 0;
 
2325
    }
 
2326
 
 
2327
    bar->leftSpeed += groupSpringForce(s,
 
2328
                                       bar->region->extents.x1,
 
2329
                                       bar->leftSpringX);
 
2330
    bar->rightSpeed += groupSpringForce(s,
 
2331
                                        bar->region->extents.x2,
 
2332
                                        bar->rightSpringX);
 
2333
 
 
2334
    if (draggedSlot)
 
2335
    {
 
2336
        int leftForce, rightForce;
 
2337
 
 
2338
        leftForce = groupDraggedSlotForce(s,
 
2339
                                          bar->region->extents.x1 -
 
2340
                                          SIZE / 2 - draggedCenterX,
 
2341
                                          abs ((bar->region->extents.y1 +
 
2342
                                                bar->region->extents.y2) / 2 -
 
2343
                                               draggedCenterY));
 
2344
 
 
2345
        rightForce = groupDraggedSlotForce (s,
 
2346
                                            bar->region->extents.x2 +
 
2347
                                            SIZE / 2 - draggedCenterX,
 
2348
                                            abs ((bar->region->extents.y1 +
 
2349
                                                  bar->region->extents.y2) / 2 -
 
2350
                                                 draggedCenterY));
 
2351
 
 
2352
        if (leftForce < 0)
 
2353
            bar->leftSpeed += leftForce;
 
2354
        if (rightForce > 0)
 
2355
            bar->rightSpeed += rightForce;
 
2356
    }
 
2357
 
 
2358
    for (slot = bar->slots; slot; slot = slot->next)
 
2359
    {
 
2360
        centerX = (slot->region->extents.x1 + slot->region->extents.x2) / 2;
 
2361
        centerY = (slot->region->extents.y1 + slot->region->extents.y2) / 2;
 
2362
 
 
2363
        slot->speed += groupSpringForce (s, centerX, slot->springX);
 
2364
 
 
2365
        if (draggedSlot && draggedSlot != slot)
 
2366
        {
 
2367
            int draggedSlotForce;
 
2368
            draggedSlotForce =
 
2369
                groupDraggedSlotForce(s, centerX - draggedCenterX,
 
2370
                                      abs (centerY - draggedCenterY));
 
2371
 
 
2372
            slot->speed += draggedSlotForce;
 
2373
            slot2 = NULL;
 
2374
 
 
2375
            if (draggedSlotForce < 0)
 
2376
            {
 
2377
                slot2 = slot->prev;
 
2378
                bar->leftSpeed += draggedSlotForce;
 
2379
            }
 
2380
            else if (draggedSlotForce > 0)
 
2381
            {
 
2382
                slot2 = slot->next;
 
2383
                bar->rightSpeed += draggedSlotForce;
 
2384
            }
 
2385
 
 
2386
            while (slot2)
 
2387
            {
 
2388
                if (slot2 != draggedSlot)
 
2389
                    slot2->speed += draggedSlotForce;
 
2390
 
 
2391
                slot2 = (draggedSlotForce < 0) ? slot2->prev : slot2->next;
 
2392
            }
 
2393
        }
 
2394
    }
 
2395
 
 
2396
    for (slot = bar->slots; slot; slot = slot->next)
 
2397
    {
 
2398
        groupApplyFriction (s, &slot->speed);
 
2399
        groupApplySpeedLimit (s, &slot->speed);
 
2400
    }
 
2401
 
 
2402
    groupApplyFriction (s, &bar->leftSpeed);
 
2403
    groupApplySpeedLimit (s, &bar->leftSpeed);
 
2404
 
 
2405
    groupApplyFriction (s, &bar->rightSpeed);
 
2406
    groupApplySpeedLimit (s, &bar->rightSpeed);
2817
2407
}
2818
2408
 
2819
2409
/*
2822
2412
 */
2823
2413
void
2824
2414
groupApplySpeeds (CompScreen     *s,
2825
 
                                  GroupSelection *group,
2826
 
                                  int            msSinceLastRepaint)
 
2415
                  GroupSelection *group,
 
2416
                  int            msSinceLastRepaint)
2827
2417
{
2828
 
        GroupTabBar     *bar = group->tabBar;
2829
 
        GroupTabBarSlot *slot;
2830
 
        int             move;
2831
 
        XRectangle      box;
2832
 
        Bool            updateTabBar = FALSE;
2833
 
 
2834
 
        box.x = bar->region->extents.x1;
2835
 
        box.y = bar->region->extents.y1;
2836
 
        box.width = bar->region->extents.x2 - bar->region->extents.x1;
2837
 
        box.height = bar->region->extents.y2 - bar->region->extents.y1;
2838
 
 
2839
 
        bar->leftMsSinceLastMove += msSinceLastRepaint;
2840
 
        bar->rightMsSinceLastMove += msSinceLastRepaint;
2841
 
 
2842
 
        /* Left */
2843
 
        move = bar->leftSpeed * bar->leftMsSinceLastMove / 1000;
2844
 
        if (move)
2845
 
        {
2846
 
                box.x += move;
2847
 
                box.width -= move;
2848
 
 
2849
 
                bar->leftMsSinceLastMove = 0;
2850
 
                updateTabBar = TRUE;
2851
 
        }
2852
 
        else if (bar->leftSpeed == 0 &&
2853
 
                         bar->region->extents.x1 != bar->leftSpringX &&
2854
 
                         (SPRING_K * abs (bar->region->extents.x1 - bar->leftSpringX) <
2855
 
                          FRICTION))
2856
 
        {
2857
 
                /* Friction is preventing from the left border to get
2858
 
                   to its original position. */
2859
 
                box.x += bar->leftSpringX - bar->region->extents.x1;
2860
 
                box.width -= bar->leftSpringX - bar->region->extents.x1;
2861
 
 
2862
 
                bar->leftMsSinceLastMove = 0;
2863
 
                updateTabBar = TRUE;
2864
 
        }
2865
 
        else if (bar->leftSpeed == 0)
2866
 
                bar->leftMsSinceLastMove = 0;
2867
 
 
2868
 
        /* Right */
2869
 
        move = bar->rightSpeed * bar->rightMsSinceLastMove / 1000;
2870
 
        if (move)
2871
 
        {
2872
 
                box.width += move;
2873
 
 
2874
 
                bar->rightMsSinceLastMove = 0;
2875
 
                updateTabBar = TRUE;
2876
 
        }
2877
 
        else if (bar->rightSpeed == 0 &&
2878
 
                         bar->region->extents.x2 != bar->rightSpringX &&
2879
 
                         (SPRING_K * abs (bar->region->extents.x2 - bar->rightSpringX) <
2880
 
                          FRICTION))
2881
 
        {
2882
 
                /* Friction is preventing from the right border to get
2883
 
                   to its original position. */
2884
 
                box.width += bar->leftSpringX - bar->region->extents.x1;
2885
 
 
2886
 
                bar->leftMsSinceLastMove = 0;
2887
 
                updateTabBar = TRUE;
2888
 
        }
2889
 
        else if (bar->rightSpeed == 0)
2890
 
                bar->rightMsSinceLastMove = 0;
2891
 
 
2892
 
        if (updateTabBar)
2893
 
                groupResizeTabBarRegion (group, &box, FALSE);
2894
 
 
2895
 
        for (slot = bar->slots; slot; slot = slot->next)
2896
 
        {
2897
 
                int slotCenter;
2898
 
 
2899
 
                slot->msSinceLastMove += msSinceLastRepaint;
2900
 
                move = slot->speed * slot->msSinceLastMove / 1000;
2901
 
                slotCenter = (slot->region->extents.x1 +
2902
 
                                          slot->region->extents.x2) / 2;
2903
 
 
2904
 
                if (move)
2905
 
                {
2906
 
                        XOffsetRegion (slot->region, move, 0);
2907
 
                        slot->msSinceLastMove = 0;
2908
 
                }
2909
 
                else if (slot->speed == 0 &&
2910
 
                                 slotCenter != slot->springX &&
2911
 
                                 SPRING_K * abs (slotCenter - slot->springX) < FRICTION)
2912
 
                {
2913
 
                        /* Friction is preventing from the slot to get
2914
 
                           to its original position. */
2915
 
 
2916
 
                        XOffsetRegion (slot->region, slot->springX - slotCenter, 0);
2917
 
                        slot->msSinceLastMove = 0;
2918
 
                }
2919
 
                else if (slot->speed == 0)
2920
 
                        slot->msSinceLastMove = 0;
2921
 
        }
 
2418
    GroupTabBar     *bar = group->tabBar;
 
2419
    GroupTabBarSlot *slot;
 
2420
    int             move;
 
2421
    XRectangle      box;
 
2422
    Bool            updateTabBar = FALSE;
 
2423
 
 
2424
    box.x = bar->region->extents.x1;
 
2425
    box.y = bar->region->extents.y1;
 
2426
    box.width = bar->region->extents.x2 - bar->region->extents.x1;
 
2427
    box.height = bar->region->extents.y2 - bar->region->extents.y1;
 
2428
 
 
2429
    bar->leftMsSinceLastMove += msSinceLastRepaint;
 
2430
    bar->rightMsSinceLastMove += msSinceLastRepaint;
 
2431
 
 
2432
    /* Left */
 
2433
    move = bar->leftSpeed * bar->leftMsSinceLastMove / 1000;
 
2434
    if (move)
 
2435
    {
 
2436
        box.x += move;
 
2437
        box.width -= move;
 
2438
 
 
2439
        bar->leftMsSinceLastMove = 0;
 
2440
        updateTabBar = TRUE;
 
2441
    }
 
2442
    else if (bar->leftSpeed == 0 &&
 
2443
             bar->region->extents.x1 != bar->leftSpringX &&
 
2444
             (SPRING_K * abs (bar->region->extents.x1 - bar->leftSpringX) <
 
2445
              FRICTION))
 
2446
    {
 
2447
        /* Friction is preventing from the left border to get
 
2448
           to its original position. */
 
2449
        box.x += bar->leftSpringX - bar->region->extents.x1;
 
2450
        box.width -= bar->leftSpringX - bar->region->extents.x1;
 
2451
 
 
2452
        bar->leftMsSinceLastMove = 0;
 
2453
        updateTabBar = TRUE;
 
2454
    }
 
2455
    else if (bar->leftSpeed == 0)
 
2456
        bar->leftMsSinceLastMove = 0;
 
2457
 
 
2458
    /* Right */
 
2459
    move = bar->rightSpeed * bar->rightMsSinceLastMove / 1000;
 
2460
    if (move)
 
2461
    {
 
2462
        box.width += move;
 
2463
 
 
2464
        bar->rightMsSinceLastMove = 0;
 
2465
        updateTabBar = TRUE;
 
2466
    }
 
2467
    else if (bar->rightSpeed == 0 &&
 
2468
             bar->region->extents.x2 != bar->rightSpringX &&
 
2469
             (SPRING_K * abs (bar->region->extents.x2 - bar->rightSpringX) <
 
2470
              FRICTION))
 
2471
    {
 
2472
        /* Friction is preventing from the right border to get
 
2473
           to its original position. */
 
2474
        box.width += bar->leftSpringX - bar->region->extents.x1;
 
2475
 
 
2476
        bar->leftMsSinceLastMove = 0;
 
2477
        updateTabBar = TRUE;
 
2478
    }
 
2479
    else if (bar->rightSpeed == 0)
 
2480
        bar->rightMsSinceLastMove = 0;
 
2481
 
 
2482
    if (updateTabBar)
 
2483
        groupResizeTabBarRegion (group, &box, FALSE);
 
2484
 
 
2485
    for (slot = bar->slots; slot; slot = slot->next)
 
2486
    {
 
2487
        int slotCenter;
 
2488
 
 
2489
        slot->msSinceLastMove += msSinceLastRepaint;
 
2490
        move = slot->speed * slot->msSinceLastMove / 1000;
 
2491
        slotCenter = (slot->region->extents.x1 +
 
2492
                      slot->region->extents.x2) / 2;
 
2493
 
 
2494
        if (move)
 
2495
        {
 
2496
            XOffsetRegion (slot->region, move, 0);
 
2497
            slot->msSinceLastMove = 0;
 
2498
        }
 
2499
        else if (slot->speed == 0 &&
 
2500
                 slotCenter != slot->springX &&
 
2501
                 SPRING_K * abs (slotCenter - slot->springX) < FRICTION)
 
2502
        {
 
2503
            /* Friction is preventing from the slot to get
 
2504
               to its original position. */
 
2505
 
 
2506
            XOffsetRegion (slot->region, slot->springX - slotCenter, 0);
 
2507
            slot->msSinceLastMove = 0;
 
2508
        }
 
2509
        else if (slot->speed == 0)
 
2510
            slot->msSinceLastMove = 0;
 
2511
    }
2922
2512
}
2923
2513
 
2924
2514
/*
2927
2517
 */
2928
2518
void
2929
2519
groupInitTabBar (GroupSelection *group,
2930
 
                                 CompWindow     *topTab)
 
2520
                 CompWindow     *topTab)
2931
2521
{
2932
 
        GroupTabBar *bar;
2933
 
        int         i;
2934
 
 
2935
 
        if (group->tabBar)
2936
 
                return;
2937
 
 
2938
 
        bar = malloc (sizeof (GroupTabBar));
2939
 
        bar->slots = NULL;
2940
 
        bar->nSlots = 0;
2941
 
        bar->bgAnimation = AnimationNone;
2942
 
        bar->bgAnimationTime = 0;
2943
 
        bar->state = PaintOff;
2944
 
        bar->animationTime = 0;
2945
 
        bar->timeoutHandle = 0;
2946
 
        bar->textLayer = NULL;
2947
 
        bar->bgLayer = NULL;
2948
 
        bar->selectionLayer = NULL;
2949
 
        bar->hoveredSlot = NULL;
2950
 
        bar->textSlot = NULL;
2951
 
        bar->oldWidth = 0;
2952
 
        group->tabBar = bar;
2953
 
 
2954
 
        bar->region = XCreateRegion();
2955
 
 
2956
 
        for (i = 0; i < group->nWins; i++)
2957
 
                groupCreateSlot (group, group->windows[i]);
2958
 
 
2959
 
        groupRecalcTabBarPos (group,
2960
 
                                                  WIN_X (topTab) + WIN_WIDTH (topTab) / 2,
2961
 
                                                  WIN_X (topTab),
2962
 
                                                  WIN_X (topTab) + WIN_WIDTH (topTab));
 
2522
    GroupTabBar *bar;
 
2523
    int         i;
 
2524
 
 
2525
    if (group->tabBar)
 
2526
        return;
 
2527
 
 
2528
    bar = malloc (sizeof (GroupTabBar));
 
2529
    if (!bar)
 
2530
        return;
 
2531
 
 
2532
    bar->slots = NULL;
 
2533
    bar->nSlots = 0;
 
2534
    bar->bgAnimation = AnimationNone;
 
2535
    bar->bgAnimationTime = 0;
 
2536
    bar->state = PaintOff;
 
2537
    bar->animationTime = 0;
 
2538
    bar->timeoutHandle = 0;
 
2539
    bar->textLayer = NULL;
 
2540
    bar->bgLayer = NULL;
 
2541
    bar->selectionLayer = NULL;
 
2542
    bar->hoveredSlot = NULL;
 
2543
    bar->textSlot = NULL;
 
2544
    bar->oldWidth = 0;
 
2545
    group->tabBar = bar;
 
2546
 
 
2547
    bar->region = XCreateRegion ();
 
2548
 
 
2549
    for (i = 0; i < group->nWins; i++)
 
2550
        groupCreateSlot (group, group->windows[i]);
 
2551
 
 
2552
    groupRecalcTabBarPos (group, WIN_CENTER_X (topTab),
 
2553
                          WIN_X (topTab), WIN_X (topTab) + WIN_WIDTH (topTab));
2963
2554
}
2964
2555
 
2965
2556
/*
2969
2560
void
2970
2561
groupDeleteTabBar (GroupSelection *group)
2971
2562
{
2972
 
        GroupTabBar *bar = group->tabBar;
2973
 
 
2974
 
        groupDestroyCairoLayer (group->screen, bar->textLayer);
2975
 
        groupDestroyCairoLayer (group->screen, bar->bgLayer);
2976
 
        groupDestroyCairoLayer (group->screen, bar->selectionLayer);
2977
 
 
2978
 
        groupDestroyInputPreventionWindow (group);
2979
 
 
2980
 
        if (bar->timeoutHandle)
2981
 
                compRemoveTimeout (bar->timeoutHandle);
2982
 
 
2983
 
        while (bar->slots)
2984
 
                groupDeleteTabBarSlot (bar, bar->slots);
2985
 
 
2986
 
        if (bar->region)
2987
 
                XDestroyRegion (bar->region);
2988
 
 
2989
 
        free (bar);
2990
 
        group->tabBar = NULL;
 
2563
    GroupTabBar *bar = group->tabBar;
 
2564
 
 
2565
    groupDestroyCairoLayer (group->screen, bar->textLayer);
 
2566
    groupDestroyCairoLayer (group->screen, bar->bgLayer);
 
2567
    groupDestroyCairoLayer (group->screen, bar->selectionLayer);
 
2568
 
 
2569
    groupDestroyInputPreventionWindow (group);
 
2570
 
 
2571
    if (bar->timeoutHandle)
 
2572
        compRemoveTimeout (bar->timeoutHandle);
 
2573
 
 
2574
    while (bar->slots)
 
2575
        groupDeleteTabBarSlot (bar, bar->slots);
 
2576
 
 
2577
    if (bar->region)
 
2578
        XDestroyRegion (bar->region);
 
2579
 
 
2580
    free (bar);
 
2581
    group->tabBar = NULL;
2991
2582
}
2992
2583
 
2993
2584
/*
2996
2587
 */
2997
2588
Bool
2998
2589
groupInitTab (CompDisplay     *d,
2999
 
                          CompAction      *action,
3000
 
                          CompActionState state,
3001
 
                          CompOption      *option,
3002
 
                          int             nOption)
 
2590
              CompAction      *action,
 
2591
              CompActionState state,
 
2592
              CompOption      *option,
 
2593
              int             nOption)
3003
2594
{
3004
 
        CompWindow *w;
3005
 
        Bool       allowUntab = TRUE;
3006
 
 
3007
 
        w = findWindowAtDisplay (d, d->activeWindow);
3008
 
        if (!w)
3009
 
                return TRUE;
3010
 
 
3011
 
        GROUP_WINDOW (w);
3012
 
 
3013
 
        if (gw->inSelection)
3014
 
        {
3015
 
                groupGroupWindows (d, action, state, option, nOption);
3016
 
                /* If the window was selected, we don't want to untab the group,
3017
 
                   because the user probably wanted to tab the selected windows. */
3018
 
                allowUntab = FALSE;
3019
 
        }
3020
 
 
3021
 
        if (!gw->group)
3022
 
                return TRUE;
3023
 
 
3024
 
        if (!gw->group->tabBar)
3025
 
                groupTabGroup (w);
3026
 
        else if (allowUntab)
3027
 
                groupUntabGroup (gw->group);
3028
 
 
3029
 
        damageScreen (w->screen);
3030
 
 
3031
 
        return TRUE;
 
2595
    Window     xid;
 
2596
    CompWindow *w;
 
2597
    Bool       allowUntab = TRUE;
 
2598
 
 
2599
    xid = getIntOptionNamed (option, nOption, "window", 0);
 
2600
    w   = findWindowAtDisplay (d, xid);
 
2601
    if (!w)
 
2602
        return TRUE;
 
2603
 
 
2604
    GROUP_WINDOW (w);
 
2605
 
 
2606
    if (gw->inSelection)
 
2607
    {
 
2608
        groupGroupWindows (d, action, state, option, nOption);
 
2609
        /* If the window was selected, we don't want to
 
2610
           untab the group, because the user probably
 
2611
           wanted to tab the selected windows. */
 
2612
        allowUntab = FALSE;
 
2613
    }
 
2614
 
 
2615
    if (!gw->group)
 
2616
        return TRUE;
 
2617
 
 
2618
    if (!gw->group->tabBar)
 
2619
        groupTabGroup (w);
 
2620
    else if (allowUntab)
 
2621
        groupUntabGroup (gw->group);
 
2622
 
 
2623
    damageScreen (w->screen);
 
2624
 
 
2625
    return TRUE;
3032
2626
}
3033
2627
 
3034
2628
/*
3036
2630
 *
3037
2631
 */
3038
2632
Bool
3039
 
groupChangeTabLeft(CompDisplay * d, CompAction * action, CompActionState state,
3040
 
               CompOption * option, int nOption)
 
2633
groupChangeTabLeft (CompDisplay     *d,
 
2634
                    CompAction      *action,
 
2635
                    CompActionState state,
 
2636
                    CompOption      *option,
 
2637
                    int             nOption)
3041
2638
{
3042
 
        CompWindow *w, *topTab;
3043
 
        
3044
 
        w = topTab = findWindowAtDisplay (d, d->activeWindow);
3045
 
        if (!w)
3046
 
                return TRUE;
3047
 
 
3048
 
        GROUP_WINDOW (w);
3049
 
        GROUP_SCREEN (w->screen);
3050
 
 
3051
 
        if (!gw->slot || !gw->group)
3052
 
                return TRUE;
3053
 
 
3054
 
        if (gw->group->nextTopTab)
3055
 
                topTab = NEXT_TOP_TAB (gw->group);
3056
 
        else if (gw->group->topTab)
3057
 
        {
3058
 
                /* If there are no tabbing animations,
3059
 
                   topTab is never NULL. */
3060
 
                topTab = TOP_TAB (gw->group);
3061
 
        }
3062
 
 
3063
 
        gw = GET_GROUP_WINDOW (topTab, gs);
3064
 
 
3065
 
        if (gw->slot->prev)
3066
 
                return groupChangeTab (gw->slot->prev, RotateLeft);
3067
 
        else
3068
 
                return groupChangeTab (gw->group->tabBar->revSlots, RotateLeft);
 
2639
    Window     xid;
 
2640
    CompWindow *w, *topTab;
 
2641
 
 
2642
    xid = getIntOptionNamed (option, nOption, "window", 0);
 
2643
    w   = topTab = findWindowAtDisplay (d, xid);
 
2644
    if (!w)
 
2645
        return TRUE;
 
2646
 
 
2647
    GROUP_WINDOW (w);
 
2648
    GROUP_SCREEN (w->screen);
 
2649
 
 
2650
    if (!gw->slot || !gw->group)
 
2651
        return TRUE;
 
2652
 
 
2653
    if (gw->group->nextTopTab)
 
2654
        topTab = NEXT_TOP_TAB (gw->group);
 
2655
    else if (gw->group->topTab)
 
2656
    {
 
2657
        /* If there are no tabbing animations,
 
2658
           topTab is never NULL. */
 
2659
        topTab = TOP_TAB (gw->group);
 
2660
    }
 
2661
 
 
2662
    gw = GET_GROUP_WINDOW (topTab, gs);
 
2663
 
 
2664
    if (gw->slot->prev)
 
2665
        return groupChangeTab (gw->slot->prev, RotateLeft);
 
2666
    else
 
2667
        return groupChangeTab (gw->group->tabBar->revSlots, RotateLeft);
3069
2668
}
3070
2669
 
3071
2670
/*
3074
2673
 */
3075
2674
Bool
3076
2675
groupChangeTabRight (CompDisplay     *d,
3077
 
                                         CompAction      *action,
3078
 
                                         CompActionState state,
3079
 
                                         CompOption      *option,
3080
 
                                         int             nOption)
 
2676
                     CompAction      *action,
 
2677
                     CompActionState state,
 
2678
                     CompOption      *option,
 
2679
                     int             nOption)
3081
2680
{
3082
 
        CompWindow *w, *topTab;
3083
 
        
3084
 
        w = topTab = findWindowAtDisplay (d, d->activeWindow);
3085
 
        if (!w)
3086
 
                return TRUE;
3087
 
 
3088
 
        GROUP_WINDOW (w);
3089
 
        GROUP_SCREEN (w->screen);
3090
 
 
3091
 
        if (!gw->slot || !gw->group)
3092
 
                return TRUE;
3093
 
 
3094
 
        if (gw->group->nextTopTab)
3095
 
                topTab = NEXT_TOP_TAB (gw->group);
3096
 
        else if (gw->group->topTab)
3097
 
        {
3098
 
                /* If there are no tabbing animations,
3099
 
                   topTab is never NULL. */
3100
 
                topTab = TOP_TAB (gw->group);
3101
 
        }
3102
 
 
3103
 
        gw = GET_GROUP_WINDOW (topTab, gs);
3104
 
 
3105
 
        if (gw->slot->next)
3106
 
                return groupChangeTab (gw->slot->next, RotateRight);
3107
 
        else
3108
 
                return groupChangeTab (gw->group->tabBar->slots, RotateRight);
 
2681
    Window     xid;
 
2682
    CompWindow *w, *topTab;
 
2683
 
 
2684
    xid = getIntOptionNamed (option, nOption, "window", 0);
 
2685
    w   = topTab = findWindowAtDisplay (d, xid);
 
2686
    if (!w)
 
2687
        return TRUE;
 
2688
 
 
2689
    GROUP_WINDOW (w);
 
2690
    GROUP_SCREEN (w->screen);
 
2691
 
 
2692
    if (!gw->slot || !gw->group)
 
2693
        return TRUE;
 
2694
 
 
2695
    if (gw->group->nextTopTab)
 
2696
        topTab = NEXT_TOP_TAB (gw->group);
 
2697
    else if (gw->group->topTab)
 
2698
    {
 
2699
        /* If there are no tabbing animations,
 
2700
           topTab is never NULL. */
 
2701
        topTab = TOP_TAB (gw->group);
 
2702
    }
 
2703
 
 
2704
    gw = GET_GROUP_WINDOW (topTab, gs);
 
2705
 
 
2706
    if (gw->slot->next)
 
2707
        return groupChangeTab (gw->slot->next, RotateRight);
 
2708
    else
 
2709
        return groupChangeTab (gw->group->tabBar->slots, RotateRight);
3109
2710
}
3110
2711
 
3111
2712
/*
3114
2715
 */
3115
2716
void
3116
2717
groupSwitchTopTabInput (GroupSelection *group,
3117
 
                                                Bool           enable)
 
2718
                        Bool           enable)
3118
2719
{
3119
 
        if (!group->tabBar || !HAS_TOP_WIN (group))
3120
 
                return;
3121
 
 
3122
 
        if (!group->inputPrevention)
3123
 
                groupCreateInputPreventionWindow (group);
3124
 
 
3125
 
        if (!enable)
3126
 
                XMapWindow (group->screen->display->display,
3127
 
                                        group->inputPrevention);
3128
 
        else
3129
 
                XUnmapWindow (group->screen->display->display,
3130
 
                                          group->inputPrevention);
3131
 
 
3132
 
        group->ipwMapped = !enable;
 
2720
    if (!group->tabBar || !HAS_TOP_WIN (group))
 
2721
        return;
 
2722
 
 
2723
    if (!group->inputPrevention)
 
2724
        groupCreateInputPreventionWindow (group);
 
2725
 
 
2726
    if (!enable)
 
2727
        XMapWindow (group->screen->display->display,
 
2728
                    group->inputPrevention);
 
2729
    else
 
2730
        XUnmapWindow (group->screen->display->display,
 
2731
                      group->inputPrevention);
 
2732
 
 
2733
    group->ipwMapped = !enable;
3133
2734
}
3134
2735
 
3135
2736
/*
3139
2740
void
3140
2741
groupCreateInputPreventionWindow (GroupSelection *group)
3141
2742
{
3142
 
        if (!group->inputPrevention)
3143
 
        {
3144
 
                XSetWindowAttributes attrib;
3145
 
                attrib.override_redirect = TRUE;
 
2743
    if (!group->inputPrevention)
 
2744
    {
 
2745
        XSetWindowAttributes attrib;
 
2746
        attrib.override_redirect = TRUE;
3146
2747
 
3147
 
                group->inputPrevention =
3148
 
                        XCreateWindow (group->screen->display->display,
3149
 
                                                   group->screen->root, -100, -100, 1, 1, 0,
3150
 
                                                   CopyFromParent, InputOnly,
3151
 
                                                   CopyFromParent, CWOverrideRedirect, &attrib);
3152
 
                group->ipwMapped = FALSE;
3153
 
        }
 
2748
        group->inputPrevention =
 
2749
            XCreateWindow (group->screen->display->display,
 
2750
                           group->screen->root, -100, -100, 1, 1, 0,
 
2751
                           CopyFromParent, InputOnly,
 
2752
                           CopyFromParent, CWOverrideRedirect, &attrib);
 
2753
        group->ipwMapped = FALSE;
 
2754
    }
3154
2755
}
3155
2756
 
3156
2757
/*
3160
2761
void
3161
2762
groupDestroyInputPreventionWindow (GroupSelection *group)
3162
2763
{
3163
 
        if (group->inputPrevention)
3164
 
        {
3165
 
                XDestroyWindow (group->screen->display->display,
3166
 
                                                group->inputPrevention);
 
2764
    if (group->inputPrevention)
 
2765
    {
 
2766
        XDestroyWindow (group->screen->display->display,
 
2767
                        group->inputPrevention);
3167
2768
 
3168
 
                group->inputPrevention = None;
3169
 
                group->ipwMapped = TRUE;
3170
 
        }
 
2769
        group->inputPrevention = None;
 
2770
        group->ipwMapped = TRUE;
 
2771
    }
3171
2772
}