~unity-team/compiz/plugins-main-trunk.fix_wrong_window_move_expo

« back to all changes in this revision

Viewing changes to resizeinfo/src/resizeinfo.cpp

  • Committer: David Barth
  • Date: 2011-03-29 16:36:40 UTC
  • Revision ID: david.barth@canonical.com-20110329163640-fpen5qsoo0lbjode
initial import from compiz-plugins-main_0.9.4git20110322.orig.tar.gz

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 *
 
3
 * Compiz metacity like info during resize
 
4
 *
 
5
 * resizeinfo.c
 
6
 *
 
7
 * Copyright (c) 2007 Robert Carr <racarr@opencompositing.org>
 
8
 *
 
9
 * Compiz resize atom usage and general cleanups by
 
10
 * Copyright (c) 2007 Danny Baumann <maniac@opencompositing.org>
 
11
 *
 
12
 * This program is free software; you can redistribute it and/or
 
13
 * modify it under the terms of the GNU General Public License
 
14
 * as published by the Free Software Foundation; either version 2
 
15
 * of the License, or (at your option) any later version.
 
16
 *
 
17
 * This program is distributed in the hope that it will be useful,
 
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
20
 * GNU General Public License for more details.
 
21
 *
 
22
 **/
 
23
 
 
24
#include "resizeinfo.h"
 
25
 
 
26
COMPIZ_PLUGIN_20090315 (resizeinfo, InfoPluginVTable);
 
27
 
 
28
/* Set up an InfoLayer to build a cairo->opengl texture pipeline */
 
29
InfoLayer::~InfoLayer ()
 
30
{
 
31
    if (cr)
 
32
        cairo_destroy (cr);
 
33
 
 
34
    if (surface)
 
35
        cairo_surface_destroy (surface);
 
36
 
 
37
    if (pixmap)
 
38
        XFreePixmap (screen->dpy (), pixmap);
 
39
}
 
40
 
 
41
/* Here 's' is Screen * 'screen' is 'CompScreen *' */
 
42
 
 
43
InfoLayer::InfoLayer () :
 
44
    valid (false),
 
45
    s (ScreenOfDisplay (screen->dpy (), screen->screenNum ())),
 
46
    pixmap (None),
 
47
    surface (NULL),
 
48
    cr (NULL)
 
49
{
 
50
    format = XRenderFindStandardFormat (screen->dpy (), PictStandardARGB32);
 
51
    if (!format)
 
52
        return;
 
53
 
 
54
    pixmap = XCreatePixmap (screen->dpy (), screen->root (),
 
55
                            RESIZE_POPUP_WIDTH, RESIZE_POPUP_HEIGHT, 32);
 
56
    if (!pixmap)
 
57
        return;
 
58
 
 
59
    surface =
 
60
        cairo_xlib_surface_create_with_xrender_format (screen->dpy (),
 
61
                                                       pixmap, s,
 
62
                                                       format,
 
63
                                                       RESIZE_POPUP_WIDTH,
 
64
                                                       RESIZE_POPUP_HEIGHT);
 
65
    if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS)
 
66
    {
 
67
        compLogMessage ("resizeinfo", CompLogLevelWarn,
 
68
                        "Could not create cairo layer surface,");
 
69
        return;
 
70
    }
 
71
 
 
72
    texture = GLTexture::bindPixmapToTexture (pixmap,
 
73
                                              RESIZE_POPUP_WIDTH,
 
74
                                              RESIZE_POPUP_HEIGHT, 32);
 
75
    if (!texture.size ())
 
76
    {
 
77
        compLogMessage ("resizeinfo", CompLogLevelWarn,
 
78
                        "Bind Pixmap to Texture failure");
 
79
        return;
 
80
    }
 
81
 
 
82
    cr = cairo_create (surface);
 
83
    if (cairo_status (cr) != CAIRO_STATUS_SUCCESS)
 
84
    {
 
85
        compLogMessage ("resizeinfo", CompLogLevelWarn,
 
86
                        "Could not create cairo context");
 
87
        return;
 
88
    }
 
89
 
 
90
    valid = true;
 
91
}
 
92
 
 
93
/* Draw the window "size" derived from the window hints.
 
94
   We calculate width or height - base_width or base_height and divide
 
95
   it by the increment in each direction. For windows like terminals
 
96
   setting the proper size hints this gives us the number of columns/rows. */
 
97
void
 
98
InfoLayer::renderText ()
 
99
{
 
100
    unsigned int         baseWidth, baseHeight;
 
101
    unsigned int         widthInc, heightInc;
 
102
    unsigned int         width, height, xv, yv;
 
103
    unsigned short       *color;
 
104
    char                 info[50];
 
105
    PangoLayout          *layout;
 
106
    PangoFontDescription *font;
 
107
    int                  w, h;
 
108
 
 
109
    INFO_SCREEN (screen);
 
110
 
 
111
    if (!valid)
 
112
        return;
 
113
 
 
114
    baseWidth = is->pWindow->sizeHints ().base_width;
 
115
    baseHeight = is->pWindow->sizeHints ().base_height;
 
116
    widthInc = is->pWindow->sizeHints ().width_inc;
 
117
    heightInc = is->pWindow->sizeHints ().height_inc;
 
118
    width = is->resizeGeometry.width;
 
119
    height = is->resizeGeometry.height;
 
120
        
 
121
    color = is->optionGetTextColor ();
 
122
 
 
123
    xv = (widthInc > 1) ? (width - baseWidth) / widthInc : width;
 
124
    yv = (heightInc > 1) ? (height - baseHeight) / heightInc : height;
 
125
 
 
126
    /* Clear the context. */
 
127
    cairo_save (cr);
 
128
    cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
 
129
    cairo_paint (cr);
 
130
    cairo_restore (cr);
 
131
    cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
 
132
 
 
133
    snprintf (info, 50, "%d x %d", xv, yv);
 
134
 
 
135
    font = pango_font_description_new ();
 
136
    layout = pango_cairo_create_layout (is->textLayer.cr);
 
137
  
 
138
    pango_font_description_set_family (font,"Sans");
 
139
    pango_font_description_set_absolute_size (font, 12 * PANGO_SCALE);
 
140
    pango_font_description_set_style (font, PANGO_STYLE_NORMAL);
 
141
    pango_font_description_set_weight (font, PANGO_WEIGHT_BOLD);
 
142
 
 
143
    pango_layout_set_font_description (layout, font);
 
144
    pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END);
 
145
    pango_layout_set_text (layout, info, -1);
 
146
  
 
147
    pango_layout_get_pixel_size (layout, &w, &h);
 
148
  
 
149
    cairo_move_to (cr, 
 
150
                   RESIZE_POPUP_WIDTH / 2.0f - w / 2.0f, 
 
151
                   RESIZE_POPUP_HEIGHT / 2.0f - h / 2.0f);
 
152
  
 
153
    pango_layout_set_width (layout, RESIZE_POPUP_WIDTH * PANGO_SCALE);
 
154
    pango_cairo_update_layout (cr, layout);
 
155
  
 
156
    cairo_set_source_rgba (cr, 
 
157
                           *(color)     / (float)0xffff,
 
158
                           *(color + 1) / (float)0xffff,
 
159
                           *(color + 2) / (float)0xffff,
 
160
                           *(color + 3) / (float)0xffff);
 
161
 
 
162
    pango_cairo_show_layout (cr, layout);
 
163
 
 
164
    pango_font_description_free (font);
 
165
    g_object_unref (layout);
 
166
}
 
167
 
 
168
/* Draw the background. We draw this on a second layer so that we do
 
169
   not have to draw it each time we have to update. Granted we could
 
170
   use some cairo trickery for this... */
 
171
void
 
172
InfoLayer::renderBackground ()
 
173
{
 
174
    cairo_pattern_t *pattern;   
 
175
    float           border = 7.5;
 
176
    int             height = RESIZE_POPUP_HEIGHT;
 
177
    int             width = RESIZE_POPUP_WIDTH;
 
178
    float           r, g, b, a;
 
179
 
 
180
    INFO_SCREEN (screen);
 
181
 
 
182
    if (!valid)
 
183
        return;
 
184
 
 
185
    cairo_set_line_width (cr, 1.0f);
 
186
 
 
187
    /* Clear */
 
188
    cairo_save (cr);
 
189
    cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
 
190
    cairo_paint (cr);
 
191
    cairo_restore (cr);
 
192
    cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
 
193
 
 
194
    /* Setup Gradient */
 
195
    pattern = cairo_pattern_create_linear (0, 0, width, height);
 
196
 
 
197
    r = is->optionGetGradient1Red () / (float)0xffff;
 
198
    g = is->optionGetGradient1Green () / (float)0xffff;
 
199
    b = is->optionGetGradient1Blue () / (float)0xffff;
 
200
    a = is->optionGetGradient1Alpha () / (float)0xffff;
 
201
    cairo_pattern_add_color_stop_rgba (pattern, 0.00f, r, g, b, a);
 
202
 
 
203
    r = is->optionGetGradient1Red () / (float)0xffff;
 
204
    g = is->optionGetGradient1Green () / (float)0xffff;
 
205
    b = is->optionGetGradient1Blue () / (float)0xffff;
 
206
    a = is->optionGetGradient1Alpha () / (float)0xffff;
 
207
    cairo_pattern_add_color_stop_rgba (pattern, 0.65f, r, g, b, a);
 
208
 
 
209
    r = is->optionGetGradient1Red () / (float)0xffff;
 
210
    g = is->optionGetGradient1Green () / (float)0xffff;
 
211
    b = is->optionGetGradient1Blue () / (float)0xffff;
 
212
    a = is->optionGetGradient1Alpha () / (float)0xffff;
 
213
    cairo_pattern_add_color_stop_rgba (pattern, 0.85f, r, g, b, a);
 
214
    cairo_set_source (cr, pattern);
 
215
        
 
216
    /* Rounded Rectangle! */
 
217
    cairo_arc (cr, border, border, border, PI, 1.5f * PI);
 
218
    cairo_arc (cr, border + width - 2 * border, border, border,
 
219
               1.5f * PI, 2.0 * PI);
 
220
    cairo_arc (cr, width - border, height - border, border, 0, PI / 2.0f);
 
221
    cairo_arc (cr, border, height - border, border,  PI / 2.0f, PI);
 
222
    cairo_close_path (cr);
 
223
    cairo_fill_preserve (cr);
 
224
        
 
225
    /* Outline */
 
226
    cairo_set_source_rgba (cr, 0.9f, 0.9f, 0.9f, 1.0f);
 
227
    cairo_stroke (cr);
 
228
        
 
229
    cairo_pattern_destroy (pattern);
 
230
}
 
231
 
 
232
static void
 
233
gradientChanged (CompOption                 *o, 
 
234
                 ResizeinfoOptions::Options num)
 
235
{
 
236
    INFO_SCREEN (screen);
 
237
 
 
238
    is->backgroundLayer.renderBackground ();
 
239
}
 
240
 
 
241
void
 
242
InfoScreen::damagePaintRegion ()
 
243
{
 
244
    int    x, y;
 
245
 
 
246
    if (!fadeTime && !drawing)
 
247
        return;
 
248
 
 
249
    x = resizeGeometry.x + resizeGeometry.width / 2.0f -
 
250
        RESIZE_POPUP_WIDTH / 2.0f;
 
251
    y = resizeGeometry.y + resizeGeometry.height / 2.0f - 
 
252
        RESIZE_POPUP_HEIGHT / 2.0f;
 
253
 
 
254
    CompRegion reg (x - 5, y - 5,
 
255
                    (x + RESIZE_POPUP_WIDTH + 5),
 
256
                    (y + RESIZE_POPUP_HEIGHT + 5));
 
257
 
 
258
    cScreen->damageRegion (reg);
 
259
}
 
260
 
 
261
/*  Handle the fade in /fade out. */
 
262
void
 
263
InfoScreen::preparePaint (int ms)
 
264
{       
 
265
    if (fadeTime)
 
266
    {
 
267
        fadeTime -= ms;
 
268
        if (fadeTime < 0)
 
269
            fadeTime = 0;
 
270
    }
 
271
 
 
272
    cScreen->preparePaint (ms);
 
273
}
 
274
 
 
275
void
 
276
InfoScreen::donePaint ()
 
277
{
 
278
    if (pWindow)
 
279
    {
 
280
        if (fadeTime)
 
281
            damagePaintRegion ();
 
282
        
 
283
        if (!fadeTime && !drawing)
 
284
        {
 
285
            pWindow = NULL;
 
286
 
 
287
            cScreen->preparePaintSetEnabled (this, false);
 
288
            gScreen->glPaintOutputSetEnabled (this, false);
 
289
            cScreen->donePaintSetEnabled (this, false);
 
290
        }
 
291
 
 
292
    }
 
293
 
 
294
    cScreen->donePaint ();
 
295
}
 
296
 
 
297
void
 
298
InfoWindow::grabNotify (int          x,
 
299
                        int          y,
 
300
                        unsigned int state,
 
301
                        unsigned int mask)
 
302
{
 
303
    INFO_SCREEN (screen);
 
304
 
 
305
    if ((!is->pWindow || !is->drawing) && !(window->state () & MAXIMIZE_STATE))
 
306
    {
 
307
        bool showInfo;
 
308
        showInfo = (((window->sizeHints ().width_inc != 1) && 
 
309
                     (window->sizeHints ().height_inc != 1)) ||
 
310
                    is->optionGetAlwaysShow ());
 
311
 
 
312
        if (showInfo && (mask & CompWindowGrabResizeMask))
 
313
        {
 
314
            is->pWindow  = window;
 
315
            is->drawing  = true;
 
316
            is->fadeTime = is->optionGetFadeTime () - is->fadeTime;
 
317
 
 
318
            is->resizeGeometry.x      = window->x ();
 
319
            is->resizeGeometry.y      = window->y ();
 
320
            is->resizeGeometry.width  = window->width ();
 
321
            is->resizeGeometry.height = window->height ();
 
322
 
 
323
            screen->handleEventSetEnabled (is, true);
 
324
        }
 
325
    }
 
326
        
 
327
    window->grabNotify (x, y, state, mask);
 
328
}
 
329
 
 
330
void
 
331
InfoWindow::ungrabNotify ()
 
332
{
 
333
    INFO_SCREEN (screen);
 
334
 
 
335
    if (window == is->pWindow)
 
336
    {
 
337
        is->drawing = false;
 
338
        is->fadeTime = is->optionGetFadeTime () - is->fadeTime;
 
339
        is->cScreen->damageScreen ();
 
340
 
 
341
        screen->handleEventSetEnabled (is, false);
 
342
        window->ungrabNotifySetEnabled (this, false);
 
343
    }
 
344
        
 
345
    window->ungrabNotify ();
 
346
}
 
347
 
 
348
/* Draw a texture at x/y on a quad of RESIZE_POPUP_WIDTH /
 
349
   RESIZE_POPUP_HEIGHT with the opacity in InfoScreen. */
 
350
void
 
351
InfoLayer::draw (int x,
 
352
                 int y)
 
353
{
 
354
    BOX   box;
 
355
    float opacity;
 
356
 
 
357
    INFO_SCREEN (screen);
 
358
 
 
359
    if (!valid)
 
360
        return;
 
361
 
 
362
    for (unsigned int i = 0; i < texture.size (); i++)
 
363
    {
 
364
 
 
365
        GLTexture         *tex = texture[i];
 
366
        GLTexture::Matrix matrix = tex->matrix ();
 
367
 
 
368
        tex->enable (GLTexture::Good);
 
369
 
 
370
        matrix.x0 -= x * matrix.xx;
 
371
        matrix.y0 -= y * matrix.yy;
 
372
 
 
373
        box.x1 = x;
 
374
        box.x2 = x + RESIZE_POPUP_WIDTH;
 
375
        box.y1 = y;
 
376
        box.y2 = y + RESIZE_POPUP_HEIGHT;
 
377
 
 
378
        opacity = (float) is->fadeTime / is->optionGetFadeTime ();
 
379
        if (is->drawing)
 
380
            opacity = 1.0f - opacity;
 
381
 
 
382
        glColor4f (opacity, opacity, opacity, opacity); 
 
383
        glBegin (GL_QUADS);
 
384
        glTexCoord2f (COMP_TEX_COORD_X (matrix, box.x1), 
 
385
                      COMP_TEX_COORD_Y (matrix, box.y2));
 
386
        glVertex2i (box.x1, box.y2);
 
387
        glTexCoord2f (COMP_TEX_COORD_X (matrix, box.x2), 
 
388
                      COMP_TEX_COORD_Y (matrix, box.y2));
 
389
        glVertex2i (box.x2, box.y2);
 
390
        glTexCoord2f (COMP_TEX_COORD_X (matrix, box.x2), 
 
391
                      COMP_TEX_COORD_Y (matrix, box.y1));
 
392
        glVertex2i (box.x2, box.y1);
 
393
        glTexCoord2f (COMP_TEX_COORD_X (matrix, box.x1), 
 
394
                      COMP_TEX_COORD_Y (matrix, box.y1));
 
395
        glVertex2i (box.x1, box.y1);    
 
396
        glEnd ();
 
397
        glColor4usv (defaultColor);
 
398
 
 
399
        tex->disable ();
 
400
    }
 
401
}
 
402
 
 
403
bool
 
404
InfoScreen::glPaintOutput (const GLScreenPaintAttrib &attrib,
 
405
                           const GLMatrix            &transform,
 
406
                           const CompRegion          &region,
 
407
                           CompOutput                *output,
 
408
                           unsigned int              mask)
 
409
{
 
410
    bool status;
 
411
  
 
412
    status = gScreen->glPaintOutput (attrib, transform, region, output, mask);
 
413
 
 
414
    if ((drawing || fadeTime) && pWindow)
 
415
    {
 
416
        GLMatrix sTransform = transform;
 
417
        int      x, y;
 
418
 
 
419
        x = resizeGeometry.x + resizeGeometry.width / 2.0f - 
 
420
            RESIZE_POPUP_WIDTH / 2.0f;
 
421
        y = resizeGeometry.y + resizeGeometry.height / 2.0f - 
 
422
            RESIZE_POPUP_HEIGHT / 2.0f;
 
423
 
 
424
        sTransform.toScreenSpace (output, -DEFAULT_Z_CAMERA);
 
425
      
 
426
        glPushMatrix ();
 
427
        glLoadMatrixf (sTransform.getMatrix ());
 
428
 
 
429
        glDisableClientState (GL_TEXTURE_COORD_ARRAY);
 
430
        glEnable (GL_BLEND);
 
431
        gScreen->setTexEnvMode (GL_MODULATE);
 
432
  
 
433
        backgroundLayer.draw (x, y);
 
434
        textLayer.draw (x, y);
 
435
  
 
436
        glDisable (GL_BLEND);
 
437
        glEnableClientState (GL_TEXTURE_COORD_ARRAY);
 
438
 
 
439
        glPopMatrix ();
 
440
    }
 
441
 
 
442
    return status;
 
443
}
 
444
 
 
445
void
 
446
InfoScreen::handleEvent (XEvent *event)
 
447
{
 
448
    switch (event->type) {
 
449
    case ClientMessage:    
 
450
        if (event->xclient.message_type == resizeInfoAtom)
 
451
        {
 
452
            CompWindow *w;
 
453
 
 
454
            w = screen->findWindow (event->xclient.window);
 
455
            if (w && w == pWindow)
 
456
            {
 
457
                resizeGeometry.x      = event->xclient.data.l[0];
 
458
                resizeGeometry.y      = event->xclient.data.l[1];
 
459
                resizeGeometry.width  = event->xclient.data.l[2];
 
460
                resizeGeometry.height = event->xclient.data.l[3];
 
461
 
 
462
                textLayer.renderText ();
 
463
 
 
464
                cScreen->preparePaintSetEnabled (this, true);
 
465
                gScreen->glPaintOutputSetEnabled (this, true);
 
466
                cScreen->donePaintSetEnabled (this, true);
 
467
 
 
468
                w->ungrabNotifySetEnabled (InfoWindow::get (w), true);
 
469
 
 
470
                damagePaintRegion ();
 
471
            }
 
472
        }
 
473
        break;
 
474
    default:
 
475
        break;
 
476
    }
 
477
 
 
478
    screen->handleEvent (event);
 
479
}
 
480
 
 
481
InfoScreen::InfoScreen (CompScreen *screen) :
 
482
    PluginClassHandler <InfoScreen, CompScreen> (screen),
 
483
    ResizeinfoOptions (),
 
484
    gScreen (GLScreen::get (screen)),
 
485
    cScreen (CompositeScreen::get (screen)),
 
486
    resizeInfoAtom (XInternAtom (screen->dpy (), "_COMPIZ_RESIZE_NOTIFY", 0)),
 
487
    pWindow (0),
 
488
    drawing (false),
 
489
    fadeTime (0)
 
490
{
 
491
    ScreenInterface::setHandler (screen);
 
492
    CompositeScreenInterface::setHandler (cScreen);
 
493
    GLScreenInterface::setHandler (gScreen);
 
494
 
 
495
    memset (&resizeGeometry, 0, sizeof (resizeGeometry));
 
496
 
 
497
    cScreen->preparePaintSetEnabled (this, false);
 
498
    gScreen->glPaintOutputSetEnabled (this, false);
 
499
    cScreen->donePaintSetEnabled (this, false);
 
500
 
 
501
    screen->handleEventSetEnabled (this, false);
 
502
 
 
503
    backgroundLayer.renderBackground ();
 
504
 
 
505
    optionSetGradient1Notify (gradientChanged);
 
506
    optionSetGradient2Notify (gradientChanged);
 
507
    optionSetGradient3Notify (gradientChanged);
 
508
}
 
509
 
 
510
InfoWindow::InfoWindow (CompWindow *window) :
 
511
    PluginClassHandler <InfoWindow, CompWindow> (window),
 
512
    window (window)
 
513
{
 
514
    WindowInterface::setHandler (window);
 
515
 
 
516
    window->ungrabNotifySetEnabled (this, false);
 
517
}
 
518
 
 
519
bool
 
520
InfoPluginVTable::init ()
 
521
{
 
522
    if (!CompPlugin::checkPluginABI ("core", CORE_ABIVERSION) ||
 
523
        !CompPlugin::checkPluginABI ("composite", COMPIZ_COMPOSITE_ABI) ||
 
524
        !CompPlugin::checkPluginABI ("opengl", COMPIZ_OPENGL_ABI))
 
525
        return false;
 
526
 
 
527
    return true;
 
528
}