2
* Copyright © 2006 Novell, Inc.
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
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.
23
* Author: David Reveman <davidr@novell.com>
30
#include <compiz-core.h>
32
static CompMetadata shotMetadata;
34
static int displayPrivateIndex;
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
41
typedef struct _ShotDisplay {
42
int screenPrivateIndex;
43
HandleEventProc handleEvent;
45
CompOption opt[SHOT_DISPLAY_OPTION_NUM];
48
typedef struct _ShotScreen {
49
PaintOutputProc paintOutput;
50
PaintScreenProc paintScreen;
57
#define GET_SHOT_DISPLAY(d) \
58
((ShotDisplay *) (d)->base.privates[displayPrivateIndex].ptr)
60
#define SHOT_DISPLAY(d) \
61
ShotDisplay *sd = GET_SHOT_DISPLAY (d)
63
#define GET_SHOT_SCREEN(s, sd) \
64
((ShotScreen *) (s)->base.privates[(sd)->screenPrivateIndex].ptr)
66
#define SHOT_SCREEN(s) \
67
ShotScreen *ss = GET_SHOT_SCREEN (s, GET_SHOT_DISPLAY (s->display))
69
#define NUM_OPTIONS(s) (sizeof ((s)->opt) / sizeof (CompOption))
73
shotInitiate (CompDisplay *d,
75
CompActionState state,
82
xid = getIntOptionNamed (option, nOption, "root", 0);
84
s = findScreenAtDisplay (d, xid);
89
if (otherScreenGrabExist (s, "screenshot", 0))
93
ss->grabIndex = pushScreenGrab (s, None, "screenshot");
95
if (state & CompActionStateInitButton)
96
action->state |= CompActionStateTermButton;
98
/* start selection screenshot rectangle */
100
ss->x1 = ss->x2 = pointerX;
101
ss->y1 = ss->y2 = pointerY;
110
shotTerminate (CompDisplay *d,
112
CompActionState state,
119
xid = getIntOptionNamed (option, nOption, "root", 0);
121
for (s = d->screens; s; s = s->next)
125
if (xid && s->root != xid)
130
removeScreenGrab (s, ss->grabIndex, NULL);
133
if (ss->x1 != ss->x2 && ss->y1 != ss->y2)
137
reg.rects = ®.extents;
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;
145
damageScreenRegion (s, ®);
150
action->state &= ~(CompActionStateTermKey | CompActionStateTermButton);
156
shotFilter (const struct dirent *d)
160
if (sscanf (d->d_name, "screenshot%d.png", &number))
167
shotSort (const void *_a,
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);
176
return strcoll ((*a)->d_name, (*b)->d_name);
182
shotPaintScreen (CompScreen *s,
189
UNWRAP (ss, s, paintScreen);
190
(*s->paintScreen) (s, outputs, numOutput, mask);
191
WRAP (ss, s, paintScreen, shotPaintScreen);
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);
207
SHOT_DISPLAY (s->display);
212
char *dir = sd->opt[SHOT_DISPLAY_OPTION_DIR].value.s;
214
buffer = malloc (sizeof (GLubyte) * w * h * 4);
217
struct dirent **namelist;
220
glReadPixels (x1, s->height - y2, w, h,
221
GL_RGBA, GL_UNSIGNED_BYTE,
224
n = scandir (dir, &namelist, shotFilter, shotSort);
232
sscanf (namelist[n - 1]->d_name,
241
sprintf (name, "screenshot%d.png", number);
243
app = sd->opt[SHOT_DISPLAY_OPTION_LAUNCH_APP].value.s;
245
if (!writeImageToFile (s->display, dir, name, "png",
248
compLogMessage (s->display, "screenshot", CompLogLevelError,
249
"failed to write screenshot image");
251
else if (*app != '\0')
255
command = malloc (strlen (app) +
260
sprintf (command, "%s %s/%s", app, dir, name);
262
runCommand (s, command);
283
shotPaintOutput (CompScreen *s,
284
const ScreenPaintAttrib *sAttrib,
285
const CompTransform *transform,
294
UNWRAP (ss, s, paintOutput);
295
status = (*s->paintOutput) (s, sAttrib, transform, region, output, mask);
296
WRAP (ss, s, paintOutput, shotPaintOutput);
298
if (status && ss->grab)
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);
311
prepareXCoords (s, output, -DEFAULT_Z_CAMERA);
313
glDisableClientState (GL_TEXTURE_COORD_ARRAY);
315
glColor4us (0x2fff, 0x2fff, 0x4fff, 0x4fff);
316
glRecti (x1, y2, x2, y1);
317
glColor4us (0x2fff, 0x2fff, 0x4fff, 0x9fff);
318
glBegin (GL_LINE_LOOP);
324
glColor4usv (defaultColor);
325
glDisable (GL_BLEND);
326
glEnableClientState (GL_TEXTURE_COORD_ARRAY);
335
shotHandleMotionEvent (CompScreen *s,
341
/* update screenshot rectangle size */
347
reg.rects = ®.extents;
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;
355
damageScreenRegion (s, ®);
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;
365
damageScreenRegion (s, ®);
372
shotHandleEvent (CompDisplay *d,
379
switch (event->type) {
381
s = findScreenAtDisplay (d, event->xmotion.root);
383
shotHandleMotionEvent (s, pointerX, pointerY);
387
s = findScreenAtDisplay (d, event->xcrossing.root);
389
shotHandleMotionEvent (s, pointerX, pointerY);
394
UNWRAP (sd, d, handleEvent);
395
(*d->handleEvent) (d, event);
396
WRAP (sd, d, handleEvent, shotHandleEvent);
400
shotGetDisplayOptions (CompPlugin *plugin,
401
CompDisplay *display,
404
SHOT_DISPLAY (display);
406
*count = NUM_OPTIONS (sd);
411
shotSetDisplayOption (CompPlugin *plugin,
412
CompDisplay *display,
414
CompOptionValue *value)
418
SHOT_DISPLAY (display);
420
o = compFindOption (sd->opt, NUM_OPTIONS (sd), name, NULL);
424
return compSetDisplayOption (display, o, value);
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 }
434
shotInitDisplay (CompPlugin *p,
439
if (!checkPluginABI ("core", CORE_ABIVERSION))
442
sd = malloc (sizeof (ShotDisplay));
446
if (!compInitDisplayOptionsFromMetadata (d,
448
shotDisplayOptionInfo,
450
SHOT_DISPLAY_OPTION_NUM))
456
sd->screenPrivateIndex = allocateScreenPrivateIndex (d);
457
if (sd->screenPrivateIndex < 0)
459
compFiniDisplayOptions (d, sd->opt, SHOT_DISPLAY_OPTION_NUM);
464
WRAP (sd, d, handleEvent, shotHandleEvent);
466
d->base.privates[displayPrivateIndex].ptr = sd;
472
shotFiniDisplay (CompPlugin *p,
477
freeScreenPrivateIndex (d, sd->screenPrivateIndex);
479
UNWRAP (sd, d, handleEvent);
481
compFiniDisplayOptions (d, sd->opt, SHOT_DISPLAY_OPTION_NUM);
487
shotInitScreen (CompPlugin *p,
492
SHOT_DISPLAY (s->display);
494
ss = malloc (sizeof (ShotScreen));
501
WRAP (ss, s, paintScreen, shotPaintScreen);
502
WRAP (ss, s, paintOutput, shotPaintOutput);
504
s->base.privates[sd->screenPrivateIndex].ptr = ss;
510
shotFiniScreen (CompPlugin *p,
515
UNWRAP (ss, s, paintScreen);
516
UNWRAP (ss, s, paintOutput);
522
shotInitObject (CompPlugin *p,
525
static InitPluginObjectProc dispTab[] = {
526
(InitPluginObjectProc) 0, /* InitCore */
527
(InitPluginObjectProc) shotInitDisplay,
528
(InitPluginObjectProc) shotInitScreen
531
RETURN_DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), TRUE, (p, o));
535
shotFiniObject (CompPlugin *p,
538
static FiniPluginObjectProc dispTab[] = {
539
(FiniPluginObjectProc) 0, /* FiniCore */
540
(FiniPluginObjectProc) shotFiniDisplay,
541
(FiniPluginObjectProc) shotFiniScreen
544
DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), (p, o));
548
shotGetObjectOptions (CompPlugin *plugin,
552
static GetPluginObjectOptionsProc dispTab[] = {
553
(GetPluginObjectOptionsProc) 0, /* GetCoreOptions */
554
(GetPluginObjectOptionsProc) shotGetDisplayOptions
557
RETURN_DISPATCH (object, dispTab, ARRAY_SIZE (dispTab),
558
(void *) (*count = 0), (plugin, object, count));
562
shotSetObjectOption (CompPlugin *plugin,
565
CompOptionValue *value)
567
static SetPluginObjectOptionProc dispTab[] = {
568
(SetPluginObjectOptionProc) 0, /* SetCoreOption */
569
(SetPluginObjectOptionProc) shotSetDisplayOption
572
RETURN_DISPATCH (object, dispTab, ARRAY_SIZE (dispTab), FALSE,
573
(plugin, object, name, value));
577
shotInit (CompPlugin *p)
579
if (!compInitPluginMetadataFromInfo (&shotMetadata,
581
shotDisplayOptionInfo,
582
SHOT_DISPLAY_OPTION_NUM,
586
displayPrivateIndex = allocateDisplayPrivateIndex ();
587
if (displayPrivateIndex < 0)
589
compFiniMetadata (&shotMetadata);
593
compAddMetadataFromFile (&shotMetadata, p->vTable->name);
599
shotFini (CompPlugin *p)
601
freeDisplayPrivateIndex (displayPrivateIndex);
602
compFiniMetadata (&shotMetadata);
605
static CompMetadata *
606
shotGetMetadata (CompPlugin *plugin)
608
return &shotMetadata;
611
static CompPluginVTable shotVTable = {
618
shotGetObjectOptions,
623
getCompPluginInfo20070830 (void)