~compiz-team/compiz/0.9.10

« back to all changes in this revision

Viewing changes to plugins/screenshot.cpp

  • Committer: Dennis kasprzyk
  • Author(s): Dennis Kasprzyk
  • Date: 2009-03-15 05:15:26 UTC
  • Revision ID: git-v1:c579970d3b62220cd2ba54e9330963554769a86c
Moved all not yet ported files into legacy directory.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright © 2006 Novell, Inc.
3
 
 *
4
 
 * Permission to use, copy, modify, distribute, and sell this software
5
 
 * and its documentation for any purpose is hereby granted without
6
 
 * fee, provided that the above copyright notice appear in all copies
7
 
 * and that both that copyright notice and this permission notice
8
 
 * appear in supporting documentation, and that the name of
9
 
 * Novell, Inc. not be used in advertising or publicity pertaining to
10
 
 * distribution of the software without specific, written prior permission.
11
 
 * Novell, Inc. makes no representations about the suitability of this
12
 
 * software for any purpose. It is provided "as is" without express or
13
 
 * implied warranty.
14
 
 *
15
 
 * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16
 
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
17
 
 * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18
 
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
19
 
 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
20
 
 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
21
 
 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22
 
 *
23
 
 * Author: David Reveman <davidr@novell.com>
24
 
 */
25
 
 
26
 
#include <stdlib.h>
27
 
#include <string.h>
28
 
#include <dirent.h>
29
 
 
30
 
#include <compiz-core.h>
31
 
 
32
 
static CompMetadata shotMetadata;
33
 
 
34
 
static int displayPrivateIndex;
35
 
 
36
 
#define SHOT_DISPLAY_OPTION_INITIATE_BUTTON 0
37
 
#define SHOT_DISPLAY_OPTION_DIR             1
38
 
#define SHOT_DISPLAY_OPTION_LAUNCH_APP      2
39
 
#define SHOT_DISPLAY_OPTION_NUM             3
40
 
 
41
 
typedef struct _ShotDisplay {
42
 
    int             screenPrivateIndex;
43
 
    HandleEventProc handleEvent;
44
 
 
45
 
    CompOption opt[SHOT_DISPLAY_OPTION_NUM];
46
 
} ShotDisplay;
47
 
 
48
 
typedef struct _ShotScreen {
49
 
    PaintOutputProc paintOutput;
50
 
    PaintScreenProc paintScreen;
51
 
    int             grabIndex;
52
 
 
53
 
    int  x1, y1, x2, y2;
54
 
    Bool grab;
55
 
} ShotScreen;
56
 
 
57
 
#define GET_SHOT_DISPLAY(d)                                       \
58
 
    ((ShotDisplay *) (d)->base.privates[displayPrivateIndex].ptr)
59
 
 
60
 
#define SHOT_DISPLAY(d)                    \
61
 
    ShotDisplay *sd = GET_SHOT_DISPLAY (d)
62
 
 
63
 
#define GET_SHOT_SCREEN(s, sd)                                        \
64
 
    ((ShotScreen *) (s)->base.privates[(sd)->screenPrivateIndex].ptr)
65
 
 
66
 
#define SHOT_SCREEN(s)                                                  \
67
 
    ShotScreen *ss = GET_SHOT_SCREEN (s, GET_SHOT_DISPLAY (s->display))
68
 
 
69
 
#define NUM_OPTIONS(s) (sizeof ((s)->opt) / sizeof (CompOption))
70
 
 
71
 
 
72
 
static Bool
73
 
shotInitiate (CompDisplay     *d,
74
 
              CompAction      *action,
75
 
              CompActionState state,
76
 
              CompOption      *option,
77
 
              int             nOption)
78
 
{
79
 
    CompScreen *s;
80
 
    Window     xid;
81
 
 
82
 
    xid = getIntOptionNamed (option, nOption, "root", 0);
83
 
 
84
 
    s = findScreenAtDisplay (d, xid);
85
 
    if (s)
86
 
    {
87
 
        SHOT_SCREEN (s);
88
 
 
89
 
        if (otherScreenGrabExist (s, "screenshot", 0))
90
 
            return FALSE;
91
 
 
92
 
        if (!ss->grabIndex)
93
 
            ss->grabIndex = pushScreenGrab (s, None, "screenshot");
94
 
 
95
 
        if (state & CompActionStateInitButton)
96
 
            action->state |= CompActionStateTermButton;
97
 
 
98
 
        /* start selection screenshot rectangle */
99
 
 
100
 
        ss->x1 = ss->x2 = pointerX;
101
 
        ss->y1 = ss->y2 = pointerY;
102
 
 
103
 
        ss->grab = TRUE;
104
 
    }
105
 
 
106
 
    return TRUE;
107
 
}
108
 
 
109
 
static Bool
110
 
shotTerminate (CompDisplay     *d,
111
 
               CompAction      *action,
112
 
               CompActionState state,
113
 
               CompOption      *option,
114
 
               int             nOption)
115
 
{
116
 
    CompScreen *s;
117
 
    Window     xid;
118
 
 
119
 
    xid = getIntOptionNamed (option, nOption, "root", 0);
120
 
 
121
 
    for (s = d->screens; s; s = s->next)
122
 
    {
123
 
        SHOT_SCREEN (s);
124
 
 
125
 
        if (xid && s->root != xid)
126
 
            continue;
127
 
 
128
 
        if (ss->grabIndex)
129
 
        {
130
 
            removeScreenGrab (s, ss->grabIndex, NULL);
131
 
            ss->grabIndex = 0;
132
 
 
133
 
            if (ss->x1 != ss->x2 && ss->y1 != ss->y2)
134
 
            {
135
 
                REGION reg;
136
 
 
137
 
                reg.rects    = &reg.extents;
138
 
                reg.numRects = 1;
139
 
 
140
 
                reg.extents.x1 = MIN (ss->x1, ss->x2) - 1;
141
 
                reg.extents.y1 = MIN (ss->y1, ss->y2) - 1;
142
 
                reg.extents.x2 = MAX (ss->x1, ss->x2) + 1;
143
 
                reg.extents.y2 = MAX (ss->y1, ss->y2) + 1;
144
 
 
145
 
                damageScreenRegion (s, &reg);
146
 
            }
147
 
        }
148
 
    }
149
 
 
150
 
    action->state &= ~(CompActionStateTermKey | CompActionStateTermButton);
151
 
 
152
 
    return FALSE;
153
 
}
154
 
 
155
 
static int
156
 
shotFilter (const struct dirent *d)
157
 
{
158
 
    int number;
159
 
 
160
 
    if (sscanf (d->d_name, "screenshot%d.png", &number))
161
 
        return 1;
162
 
 
163
 
    return 0;
164
 
}
165
 
 
166
 
static int
167
 
shotSort (const void *_a,
168
 
          const void *_b)
169
 
{
170
 
    struct dirent **a = (struct dirent **) _a;
171
 
    struct dirent **b = (struct dirent **) _b;
172
 
    int           al = strlen ((*a)->d_name);
173
 
    int           bl = strlen ((*b)->d_name);
174
 
 
175
 
    if (al == bl)
176
 
        return strcoll ((*a)->d_name, (*b)->d_name);
177
 
    else
178
 
        return al - bl;
179
 
}
180
 
 
181
 
static void
182
 
shotPaintScreen (CompScreen   *s,
183
 
                 CompOutput   *outputs,
184
 
                 int          numOutput,  
185
 
                 unsigned int mask)
186
 
{
187
 
    SHOT_SCREEN (s);
188
 
 
189
 
    UNWRAP (ss, s, paintScreen);
190
 
    (*s->paintScreen) (s, outputs, numOutput, mask);
191
 
    WRAP (ss, s, paintScreen, shotPaintScreen);
192
 
 
193
 
    if (ss->grab)
194
 
    {
195
 
        int x1, x2, y1, y2;
196
 
 
197
 
        x1 = MIN (ss->x1, ss->x2);
198
 
        y1 = MIN (ss->y1, ss->y2);
199
 
        x2 = MAX (ss->x1, ss->x2);
200
 
        y2 = MAX (ss->y1, ss->y2);
201
 
        
202
 
        if (!ss->grabIndex)
203
 
        {
204
 
            int w = x2 - x1;
205
 
            int h = y2 - y1;
206
 
 
207
 
            SHOT_DISPLAY (s->display);
208
 
 
209
 
            if (w && h)
210
 
            {
211
 
                GLubyte *buffer;
212
 
                char    *dir = sd->opt[SHOT_DISPLAY_OPTION_DIR].value.s;
213
 
 
214
 
                buffer = malloc (sizeof (GLubyte) * w * h * 4);
215
 
                if (buffer)
216
 
                {
217
 
                    struct dirent **namelist;
218
 
                    int           n;
219
 
 
220
 
                    glReadPixels (x1, s->height - y2, w, h,
221
 
                                  GL_RGBA, GL_UNSIGNED_BYTE,
222
 
                                  (GLvoid *) buffer);
223
 
 
224
 
                    n = scandir (dir, &namelist, shotFilter, shotSort);
225
 
                    if (n >= 0)
226
 
                    {
227
 
                        char name[256];
228
 
                        char *app;
229
 
                        int  number = 0;
230
 
 
231
 
                        if (n > 0)
232
 
                            sscanf (namelist[n - 1]->d_name,
233
 
                                    "screenshot%d.png",
234
 
                                    &number);
235
 
 
236
 
                        number++;
237
 
 
238
 
                        if (n)
239
 
                            free (namelist);
240
 
 
241
 
                        sprintf (name, "screenshot%d.png", number);
242
 
 
243
 
                        app = sd->opt[SHOT_DISPLAY_OPTION_LAUNCH_APP].value.s;
244
 
 
245
 
                        if (!writeImageToFile (s->display, dir, name, "png",
246
 
                                               w, h, buffer))
247
 
                        {
248
 
                            compLogMessage (s->display, "screenshot", CompLogLevelError,
249
 
                                            "failed to write screenshot image");
250
 
                        }
251
 
                        else if (*app != '\0')
252
 
                        {
253
 
                            char *command;
254
 
 
255
 
                            command = malloc (strlen (app) +
256
 
                                              strlen (dir) +
257
 
                                              strlen (name) + 3);
258
 
                            if (command)
259
 
                            {
260
 
                                sprintf (command, "%s %s/%s", app, dir, name);
261
 
 
262
 
                                runCommand (s, command);
263
 
 
264
 
                                free (command);
265
 
                            }
266
 
                        }
267
 
                    }
268
 
                    else
269
 
                    {
270
 
                        perror (dir);
271
 
                    }
272
 
 
273
 
                    free (buffer);
274
 
                }
275
 
            }
276
 
 
277
 
            ss->grab = FALSE;
278
 
        }
279
 
    }
280
 
}
281
 
 
282
 
static Bool
283
 
shotPaintOutput (CompScreen              *s,
284
 
                 const ScreenPaintAttrib *sAttrib,
285
 
                 const CompTransform     *transform,
286
 
                 Region                  region,
287
 
                 CompOutput              *output,
288
 
                 unsigned int            mask)
289
 
{
290
 
    Bool status;
291
 
 
292
 
    SHOT_SCREEN (s);
293
 
 
294
 
    UNWRAP (ss, s, paintOutput);
295
 
    status = (*s->paintOutput) (s, sAttrib, transform, region, output, mask);
296
 
    WRAP (ss, s, paintOutput, shotPaintOutput);
297
 
 
298
 
    if (status && ss->grab)
299
 
    {
300
 
        int x1, x2, y1, y2;
301
 
 
302
 
        x1 = MIN (ss->x1, ss->x2);
303
 
        y1 = MIN (ss->y1, ss->y2);
304
 
        x2 = MAX (ss->x1, ss->x2);
305
 
        y2 = MAX (ss->y1, ss->y2);
306
 
 
307
 
        if (ss->grabIndex)
308
 
        {
309
 
            glPushMatrix ();
310
 
 
311
 
            prepareXCoords (s, output, -DEFAULT_Z_CAMERA);
312
 
 
313
 
            glDisableClientState (GL_TEXTURE_COORD_ARRAY);
314
 
            glEnable (GL_BLEND);
315
 
            glColor4us (0x2fff, 0x2fff, 0x4fff, 0x4fff);
316
 
            glRecti (x1, y2, x2, y1);
317
 
            glColor4us (0x2fff, 0x2fff, 0x4fff, 0x9fff);
318
 
            glBegin (GL_LINE_LOOP);
319
 
            glVertex2i (x1, y1);
320
 
            glVertex2i (x2, y1);
321
 
            glVertex2i (x2, y2);
322
 
            glVertex2i (x1, y2);
323
 
            glEnd ();
324
 
            glColor4usv (defaultColor);
325
 
            glDisable (GL_BLEND);
326
 
            glEnableClientState (GL_TEXTURE_COORD_ARRAY);
327
 
            glPopMatrix ();
328
 
        }
329
 
    }
330
 
 
331
 
    return status;
332
 
}
333
 
 
334
 
static void
335
 
shotHandleMotionEvent (CompScreen *s,
336
 
                       int        xRoot,
337
 
                       int        yRoot)
338
 
{
339
 
    SHOT_SCREEN (s);
340
 
 
341
 
    /* update screenshot rectangle size */
342
 
 
343
 
    if (ss->grabIndex)
344
 
    {
345
 
        REGION reg;
346
 
 
347
 
        reg.rects    = &reg.extents;
348
 
        reg.numRects = 1;
349
 
 
350
 
        reg.extents.x1 = MIN (ss->x1, ss->x2) - 1;
351
 
        reg.extents.y1 = MIN (ss->y1, ss->y2) - 1;
352
 
        reg.extents.x2 = MAX (ss->x1, ss->x2) + 1;
353
 
        reg.extents.y2 = MAX (ss->y1, ss->y2) + 1;
354
 
 
355
 
        damageScreenRegion (s, &reg);
356
 
 
357
 
        ss->x2 = xRoot;
358
 
        ss->y2 = yRoot;
359
 
 
360
 
        reg.extents.x1 = MIN (ss->x1, ss->x2) - 1;
361
 
        reg.extents.y1 = MIN (ss->y1, ss->y2) - 1;
362
 
        reg.extents.x2 = MAX (ss->x1, ss->x2) + 1;
363
 
        reg.extents.y2 = MAX (ss->y1, ss->y2) + 1;
364
 
 
365
 
        damageScreenRegion (s, &reg);
366
 
 
367
 
        damageScreen (s);
368
 
    }
369
 
}
370
 
 
371
 
static void
372
 
shotHandleEvent (CompDisplay *d,
373
 
                 XEvent      *event)
374
 
{
375
 
    CompScreen *s;
376
 
 
377
 
    SHOT_DISPLAY (d);
378
 
 
379
 
    switch (event->type) {
380
 
    case MotionNotify:
381
 
        s = findScreenAtDisplay (d, event->xmotion.root);
382
 
        if (s)
383
 
            shotHandleMotionEvent (s, pointerX, pointerY);
384
 
        break;
385
 
    case EnterNotify:
386
 
    case LeaveNotify:
387
 
        s = findScreenAtDisplay (d, event->xcrossing.root);
388
 
        if (s)
389
 
            shotHandleMotionEvent (s, pointerX, pointerY);
390
 
    default:
391
 
        break;
392
 
    }
393
 
 
394
 
    UNWRAP (sd, d, handleEvent);
395
 
    (*d->handleEvent) (d, event);
396
 
    WRAP (sd, d, handleEvent, shotHandleEvent);
397
 
}
398
 
 
399
 
static CompOption *
400
 
shotGetDisplayOptions (CompPlugin  *plugin,
401
 
                       CompDisplay *display,
402
 
                       int         *count)
403
 
{
404
 
    SHOT_DISPLAY (display);
405
 
 
406
 
    *count = NUM_OPTIONS (sd);
407
 
    return sd->opt;
408
 
}
409
 
 
410
 
static Bool
411
 
shotSetDisplayOption (CompPlugin      *plugin,
412
 
                      CompDisplay     *display,
413
 
                      const char      *name,
414
 
                      CompOptionValue *value)
415
 
{
416
 
    CompOption *o;
417
 
 
418
 
    SHOT_DISPLAY (display);
419
 
 
420
 
    o = compFindOption (sd->opt, NUM_OPTIONS (sd), name, NULL);
421
 
    if (!o)
422
 
        return FALSE;
423
 
 
424
 
    return compSetDisplayOption (display, o, value);
425
 
}
426
 
 
427
 
static const CompMetadataOptionInfo shotDisplayOptionInfo[] = {
428
 
    { "initiate_button", "button", 0, shotInitiate, shotTerminate },
429
 
    { "directory", "string", 0, 0, 0 },
430
 
    { "launch_app", "string", 0, 0, 0 }
431
 
};
432
 
 
433
 
static Bool
434
 
shotInitDisplay (CompPlugin  *p,
435
 
                 CompDisplay *d)
436
 
{
437
 
    ShotDisplay *sd;
438
 
 
439
 
    if (!checkPluginABI ("core", CORE_ABIVERSION))
440
 
        return FALSE;
441
 
 
442
 
    sd = malloc (sizeof (ShotDisplay));
443
 
    if (!sd)
444
 
        return FALSE;
445
 
 
446
 
    if (!compInitDisplayOptionsFromMetadata (d,
447
 
                                             &shotMetadata,
448
 
                                             shotDisplayOptionInfo,
449
 
                                             sd->opt,
450
 
                                             SHOT_DISPLAY_OPTION_NUM))
451
 
    {
452
 
        free (sd);
453
 
        return FALSE;
454
 
    }
455
 
 
456
 
    sd->screenPrivateIndex = allocateScreenPrivateIndex (d);
457
 
    if (sd->screenPrivateIndex < 0)
458
 
    {
459
 
        compFiniDisplayOptions (d, sd->opt, SHOT_DISPLAY_OPTION_NUM);
460
 
        free (sd);
461
 
        return FALSE;
462
 
    }
463
 
 
464
 
    WRAP (sd, d, handleEvent, shotHandleEvent);
465
 
 
466
 
    d->base.privates[displayPrivateIndex].ptr = sd;
467
 
 
468
 
    return TRUE;
469
 
}
470
 
 
471
 
static void
472
 
shotFiniDisplay (CompPlugin  *p,
473
 
                 CompDisplay *d)
474
 
{
475
 
    SHOT_DISPLAY (d);
476
 
 
477
 
    freeScreenPrivateIndex (d, sd->screenPrivateIndex);
478
 
 
479
 
    UNWRAP (sd, d, handleEvent);
480
 
 
481
 
    compFiniDisplayOptions (d, sd->opt, SHOT_DISPLAY_OPTION_NUM);
482
 
 
483
 
    free (sd);
484
 
}
485
 
 
486
 
static Bool
487
 
shotInitScreen (CompPlugin *p,
488
 
                CompScreen *s)
489
 
{
490
 
    ShotScreen *ss;
491
 
 
492
 
    SHOT_DISPLAY (s->display);
493
 
 
494
 
    ss = malloc (sizeof (ShotScreen));
495
 
    if (!ss)
496
 
        return FALSE;
497
 
 
498
 
    ss->grabIndex = 0;
499
 
    ss->grab      = FALSE;
500
 
 
501
 
    WRAP (ss, s, paintScreen, shotPaintScreen);
502
 
    WRAP (ss, s, paintOutput, shotPaintOutput);
503
 
 
504
 
    s->base.privates[sd->screenPrivateIndex].ptr = ss;
505
 
 
506
 
    return TRUE;
507
 
}
508
 
 
509
 
static void
510
 
shotFiniScreen (CompPlugin *p,
511
 
                CompScreen *s)
512
 
{
513
 
    SHOT_SCREEN (s);
514
 
 
515
 
    UNWRAP (ss, s, paintScreen);
516
 
    UNWRAP (ss, s, paintOutput);
517
 
 
518
 
    free (ss);
519
 
}
520
 
 
521
 
static CompBool
522
 
shotInitObject (CompPlugin *p,
523
 
                CompObject *o)
524
 
{
525
 
    static InitPluginObjectProc dispTab[] = {
526
 
        (InitPluginObjectProc) 0, /* InitCore */
527
 
        (InitPluginObjectProc) shotInitDisplay,
528
 
        (InitPluginObjectProc) shotInitScreen
529
 
    };
530
 
 
531
 
    RETURN_DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), TRUE, (p, o));
532
 
}
533
 
 
534
 
static void
535
 
shotFiniObject (CompPlugin *p,
536
 
                CompObject *o)
537
 
{
538
 
    static FiniPluginObjectProc dispTab[] = {
539
 
        (FiniPluginObjectProc) 0, /* FiniCore */
540
 
        (FiniPluginObjectProc) shotFiniDisplay,
541
 
        (FiniPluginObjectProc) shotFiniScreen
542
 
    };
543
 
 
544
 
    DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), (p, o));
545
 
}
546
 
 
547
 
static CompOption *
548
 
shotGetObjectOptions (CompPlugin *plugin,
549
 
                      CompObject *object,
550
 
                      int        *count)
551
 
{
552
 
    static GetPluginObjectOptionsProc dispTab[] = {
553
 
        (GetPluginObjectOptionsProc) 0, /* GetCoreOptions */
554
 
        (GetPluginObjectOptionsProc) shotGetDisplayOptions
555
 
    };
556
 
 
557
 
    RETURN_DISPATCH (object, dispTab, ARRAY_SIZE (dispTab),
558
 
                     (void *) (*count = 0), (plugin, object, count));
559
 
}
560
 
 
561
 
static CompBool
562
 
shotSetObjectOption (CompPlugin      *plugin,
563
 
                     CompObject      *object,
564
 
                     const char      *name,
565
 
                     CompOptionValue *value)
566
 
{
567
 
    static SetPluginObjectOptionProc dispTab[] = {
568
 
        (SetPluginObjectOptionProc) 0, /* SetCoreOption */
569
 
        (SetPluginObjectOptionProc) shotSetDisplayOption
570
 
    };
571
 
 
572
 
    RETURN_DISPATCH (object, dispTab, ARRAY_SIZE (dispTab), FALSE,
573
 
                     (plugin, object, name, value));
574
 
}
575
 
 
576
 
static Bool
577
 
shotInit (CompPlugin *p)
578
 
{
579
 
    if (!compInitPluginMetadataFromInfo (&shotMetadata,
580
 
                                         p->vTable->name,
581
 
                                         shotDisplayOptionInfo,
582
 
                                         SHOT_DISPLAY_OPTION_NUM,
583
 
                                         0, 0))
584
 
        return FALSE;
585
 
 
586
 
    displayPrivateIndex = allocateDisplayPrivateIndex ();
587
 
    if (displayPrivateIndex < 0)
588
 
    {
589
 
        compFiniMetadata (&shotMetadata);
590
 
        return FALSE;
591
 
    }
592
 
 
593
 
    compAddMetadataFromFile (&shotMetadata, p->vTable->name);
594
 
 
595
 
    return TRUE;
596
 
}
597
 
 
598
 
static void
599
 
shotFini (CompPlugin *p)
600
 
{
601
 
    freeDisplayPrivateIndex (displayPrivateIndex);
602
 
    compFiniMetadata (&shotMetadata);
603
 
}
604
 
 
605
 
static CompMetadata *
606
 
shotGetMetadata (CompPlugin *plugin)
607
 
{
608
 
    return &shotMetadata;
609
 
}
610
 
 
611
 
static CompPluginVTable shotVTable = {
612
 
    "screenshot",
613
 
    shotGetMetadata,
614
 
    shotInit,
615
 
    shotFini,
616
 
    shotInitObject,
617
 
    shotFiniObject,
618
 
    shotGetObjectOptions,
619
 
    shotSetObjectOption
620
 
};
621
 
 
622
 
CompPluginVTable *
623
 
getCompPluginInfo20070830 (void)
624
 
{
625
 
    return &shotVTable;
626
 
}