~shnatsel/+junk/cairo-compmgr

« back to all changes in this revision

Viewing changes to plugins/magnifier/ccm-magnifier.c

  • Committer: Sergey "Shnatsel" Davidoff
  • Date: 2012-03-04 22:53:22 UTC
  • Revision ID: shnatsel@gmail.com-20120304225322-q2hz82j51yxv1qqw
fixed up build dependencies

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4; tab-width: 4 -*- */
 
2
/*
 
3
 * cairo-compmgr
 
4
 * Copyright (C) Nicolas Bruguier 2007-2010 <gandalfn@club-internet.fr>
 
5
 *               Carlos Diógenes  2007 <cerdiogenes@gmail.com>
 
6
 * 
 
7
 * cairo-compmgr is free software; you can redistribute it and/or
 
8
 * modify it under the terms of the GNU Lesser General Public
 
9
 * License as published by the Free Software Foundation; either
 
10
 * version 2.1 of the License, or (at your option) any later version.
 
11
 * 
 
12
 * cairo-compmgr is distributed in the hope that it will be useful,
 
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
15
 * Lesser General Public License for more details.
 
16
 * 
 
17
 * You should have received a copy of the GNU Lesser General Public
 
18
 * License along with cairo-compmgr.  If not, write to:
 
19
 *      The Free Software Foundation, Inc.,
 
20
 *      51 Franklin Street, Fifth Floor
 
21
 *      Boston, MA  02110-1301, USA.
 
22
 */
 
23
#include <stdio.h>
 
24
#include <string.h>
 
25
#include <math.h>
 
26
#include <X11/extensions/Xfixes.h>
 
27
 
 
28
#include "ccm-debug.h"
 
29
#include "ccm-config.h"
 
30
#include "ccm-drawable.h"
 
31
#include "ccm-window.h"
 
32
#include "ccm-display.h"
 
33
#include "ccm-screen.h"
 
34
#include "ccm-magnifier.h"
 
35
#include "ccm-keybind.h"
 
36
#include "ccm-cairo-utils.h"
 
37
#include "ccm-timeline.h"
 
38
#include "ccm.h"
 
39
 
 
40
#define CCM_MAGNIFIER_WINDOW_INFO_WIDTH 30
 
41
#define CCM_MAGNIFIER_WINDOW_INFO_HEIGHT 7
 
42
 
 
43
enum
 
44
{
 
45
    CCM_MAGNIFIER_ENABLE,
 
46
    CCM_MAGNIFIER_ZOOM_LEVEL,
 
47
    CCM_MAGNIFIER_ZOOM_QUALITY,
 
48
    CCM_MAGNIFIER_X,
 
49
    CCM_MAGNIFIER_Y,
 
50
    CCM_MAGNIFIER_HEIGHT,
 
51
    CCM_MAGNIFIER_WIDTH,
 
52
    CCM_MAGNIFIER_RESTRICT_AREA_X,
 
53
    CCM_MAGNIFIER_RESTRICT_AREA_Y,
 
54
    CCM_MAGNIFIER_RESTRICT_AREA_WIDTH,
 
55
    CCM_MAGNIFIER_RESTRICT_AREA_HEIGHT,
 
56
    CCM_MAGNIFIER_BORDER,
 
57
    CCM_MAGNIFIER_SHORTCUT,
 
58
    CCM_MAGNIFIER_SHADE_DESKTOP,
 
59
    CCM_MAGNIFIER_OPTION_N
 
60
};
 
61
 
 
62
static const gchar *CCMMagnifierOptionKeys[CCM_MAGNIFIER_OPTION_N] = {
 
63
    "enable",
 
64
    "zoom-level",
 
65
    "zoom-quality",
 
66
    "x",
 
67
    "y",
 
68
    "height",
 
69
    "width",
 
70
    "restrict_area_x",
 
71
    "restrict_area_y",
 
72
    "restrict_area_width",
 
73
    "restrict_area_height",
 
74
    "border",
 
75
    "shortcut",
 
76
    "shade_desktop"
 
77
};
 
78
 
 
79
typedef struct
 
80
{
 
81
    CCMPluginOptions parent;
 
82
 
 
83
    gboolean enabled;
 
84
    gchar* shortcut;
 
85
 
 
86
    gfloat scale;
 
87
    gfloat new_scale;
 
88
 
 
89
    gboolean shade;
 
90
 
 
91
    cairo_rectangle_t restrict_area;
 
92
    cairo_rectangle_t area;
 
93
    cairo_filter_t quality;
 
94
 
 
95
    int border;
 
96
} CCMMagnifierOptions;
 
97
 
 
98
static void ccm_magnifier_screen_iface_init (CCMScreenPluginClass * iface);
 
99
static void ccm_magnifier_window_iface_init (CCMWindowPluginClass * iface);
 
100
static void ccm_magnifier_on_option_changed (CCMPlugin * plugin, int index);
 
101
static void ccm_magnifier_on_new_frame (CCMMagnifier * self, int num_frame,
 
102
                                        CCMTimeline * timeline);
 
103
 
 
104
CCM_DEFINE_PLUGIN_WITH_OPTIONS (CCMMagnifier, ccm_magnifier, CCM_TYPE_PLUGIN,
 
105
                                CCM_IMPLEMENT_INTERFACE (ccm_magnifier,
 
106
                                                         CCM_TYPE_SCREEN_PLUGIN,
 
107
                                                         ccm_magnifier_screen_iface_init);
 
108
                                CCM_IMPLEMENT_INTERFACE (ccm_magnifier,
 
109
                                                         CCM_TYPE_WINDOW_PLUGIN,
 
110
                                                         ccm_magnifier_window_iface_init))
 
111
struct _CCMMagnifierPrivate
 
112
{
 
113
    CCMScreen * screen;
 
114
 
 
115
    int x_offset;
 
116
    int y_offset;
 
117
    cairo_surface_t * surface;
 
118
    CCMRegion * damaged;
 
119
    CCMKeybind * keybind;
 
120
 
 
121
    cairo_surface_t * surface_window_info;
 
122
    CCMTimeline * timeline;
 
123
};
 
124
 
 
125
#define CCM_MAGNIFIER_GET_PRIVATE(o)  \
 
126
(G_TYPE_INSTANCE_GET_PRIVATE ((o), CCM_TYPE_MAGNIFIER, CCMMagnifierPrivate))
 
127
 
 
128
static void
 
129
ccm_magnifier_options_init (CCMMagnifierOptions* self)
 
130
{
 
131
    self->enabled = FALSE;
 
132
    self->shade = TRUE;
 
133
    self->scale = 1.0f;
 
134
    self->new_scale = 1.0f;
 
135
    self->quality = CAIRO_FILTER_FAST;
 
136
    self->shortcut = NULL;
 
137
    self->border = 0;
 
138
    bzero (&self->area, sizeof (cairo_rectangle_t));
 
139
    bzero (&self->restrict_area, sizeof (cairo_rectangle_t));
 
140
}
 
141
 
 
142
static void
 
143
ccm_magnifier_options_finalize (CCMMagnifierOptions* self)
 
144
{
 
145
    if (self->shortcut) g_free(self->shortcut);
 
146
}
 
147
 
 
148
static void
 
149
ccm_magnifier_options_get_restrict_area (CCMMagnifierOptions* self)
 
150
{
 
151
    GError *error = NULL;
 
152
    gint val, real;
 
153
    gdouble x, y, width, height;
 
154
    CCMDisplay* display = ccm_display_get_default();
 
155
    Screen* screen = ScreenOfDisplay(CCM_DISPLAY_XDISPLAY(display),
 
156
                                     ccm_plugin_options_get_screen_num(CCM_PLUGIN_OPTIONS(self)));
 
157
 
 
158
    real = ccm_config_get_integer (ccm_plugin_options_get_config(CCM_PLUGIN_OPTIONS(self), 
 
159
                                                                 CCM_MAGNIFIER_RESTRICT_AREA_WIDTH),
 
160
                                   &error);
 
161
    if (error)
 
162
    {
 
163
        g_error_free (error);
 
164
        error = NULL;
 
165
        real = -1;
 
166
    }
 
167
    if (real < 0)
 
168
    {
 
169
        self->restrict_area.width = screen->width;
 
170
    }
 
171
    else
 
172
    {
 
173
        val = MAX (0, real);
 
174
        val = MIN (screen->width, val);
 
175
        if (real != val)
 
176
            ccm_config_set_integer (ccm_plugin_options_get_config (CCM_PLUGIN_OPTIONS(self), 
 
177
                                                                   CCM_MAGNIFIER_RESTRICT_AREA_WIDTH),
 
178
                                    val, NULL);
 
179
 
 
180
        width = val;
 
181
        if (self->restrict_area.width != width)
 
182
            self->restrict_area.width = width;
 
183
    }
 
184
 
 
185
    real = ccm_config_get_integer (ccm_plugin_options_get_config (CCM_PLUGIN_OPTIONS(self), 
 
186
                                                                  CCM_MAGNIFIER_RESTRICT_AREA_HEIGHT),
 
187
                                   &error);
 
188
    if (error)
 
189
    {
 
190
        g_error_free (error);
 
191
        error = NULL;
 
192
        real = -1;
 
193
    }
 
194
    if (real < 0)
 
195
    {
 
196
        self->restrict_area.height = screen->height;
 
197
    }
 
198
    else
 
199
    {
 
200
        val = MAX (0, real);
 
201
        val = MIN (screen->height, val);
 
202
        if (real != val)
 
203
            ccm_config_set_integer (ccm_plugin_options_get_config (CCM_PLUGIN_OPTIONS(self), 
 
204
                                                                   CCM_MAGNIFIER_RESTRICT_AREA_HEIGHT),
 
205
                                    val, NULL);
 
206
 
 
207
        height = val;
 
208
        if (self->restrict_area.height != height)
 
209
            self->restrict_area.height = height;
 
210
    }
 
211
 
 
212
    real = ccm_config_get_integer (ccm_plugin_options_get_config (CCM_PLUGIN_OPTIONS(self), 
 
213
                                                                  CCM_MAGNIFIER_RESTRICT_AREA_X), 
 
214
                                   &error);
 
215
    if (error)
 
216
    {
 
217
        g_error_free (error);
 
218
        error = NULL;
 
219
        real = -1;
 
220
    }
 
221
    if (real < 0)
 
222
    {
 
223
        self->restrict_area.x = 0;
 
224
    }
 
225
    else
 
226
    {
 
227
        val = MAX (0, real);
 
228
        val = MIN (self->restrict_area.width, val);
 
229
        if (real != val)
 
230
            ccm_config_set_integer (ccm_plugin_options_get_config(CCM_PLUGIN_OPTIONS(self), 
 
231
                                                                  CCM_MAGNIFIER_RESTRICT_AREA_X), 
 
232
                                    val, NULL);
 
233
 
 
234
        x = val;
 
235
        if (self->restrict_area.x != x)
 
236
            self->restrict_area.x = x;
 
237
    }
 
238
 
 
239
    real = ccm_config_get_integer (ccm_plugin_options_get_config (CCM_PLUGIN_OPTIONS(self), 
 
240
                                                                  CCM_MAGNIFIER_RESTRICT_AREA_Y), 
 
241
                                   &error);
 
242
    if (error)
 
243
    {
 
244
        g_error_free (error);
 
245
        error = NULL;
 
246
        real = -1;
 
247
    }
 
248
    if (real < 0)
 
249
    {
 
250
        self->restrict_area.y = 0;
 
251
    }
 
252
    else
 
253
    {
 
254
        val = MAX (0, real);
 
255
        val = MIN (self->restrict_area.height, val);
 
256
        if (real != val)
 
257
            ccm_config_set_integer (ccm_plugin_options_get_config (CCM_PLUGIN_OPTIONS(self), 
 
258
                                                                   CCM_MAGNIFIER_RESTRICT_AREA_Y), 
 
259
                                    val, NULL);
 
260
 
 
261
        y = val;
 
262
        if (self->restrict_area.y != y)
 
263
            self->restrict_area.y = y;
 
264
    }
 
265
}
 
266
 
 
267
static void
 
268
ccm_magnifier_options_get_size (CCMMagnifierOptions* self)
 
269
{
 
270
    GError *error = NULL;
 
271
    gint val, real;
 
272
    gdouble x, y, width, height;
 
273
    CCMDisplay* display = ccm_display_get_default();
 
274
    Screen* screen = ScreenOfDisplay(CCM_DISPLAY_XDISPLAY(display),
 
275
                                     ccm_plugin_options_get_screen_num(CCM_PLUGIN_OPTIONS(self)));
 
276
 
 
277
    self->area.x = 0;
 
278
    self->area.y = 0;
 
279
 
 
280
    real = ccm_config_get_integer (ccm_plugin_options_get_config (CCM_PLUGIN_OPTIONS(self), 
 
281
                                                                  CCM_MAGNIFIER_WIDTH), 
 
282
                                   &error);
 
283
    if (error)
 
284
    {
 
285
        g_error_free (error);
 
286
        error = NULL;
 
287
        real = 80;
 
288
    }
 
289
    val = MAX (10, real);
 
290
    val = MIN (80, val);
 
291
    if (real != val)
 
292
        ccm_config_set_integer (ccm_plugin_options_get_config (CCM_PLUGIN_OPTIONS(self), 
 
293
                                                               CCM_MAGNIFIER_WIDTH), 
 
294
                                val, NULL);
 
295
 
 
296
    width = (gdouble) self->restrict_area.width * (gdouble) val / 100.0;
 
297
    if (self->area.width != width)
 
298
        self->area.width = width;
 
299
 
 
300
    real = ccm_config_get_integer (ccm_plugin_options_get_config (CCM_PLUGIN_OPTIONS(self), 
 
301
                                                                  CCM_MAGNIFIER_HEIGHT), 
 
302
                                   &error);
 
303
    if (error)
 
304
    {
 
305
        g_error_free (error);
 
306
        error = NULL;
 
307
        real = 80;
 
308
    }
 
309
    val = MAX (10, real);
 
310
    val = MIN (80, val);
 
311
    if (real != val) ccm_config_set_integer (ccm_plugin_options_get_config (CCM_PLUGIN_OPTIONS(self), 
 
312
                                                                            CCM_MAGNIFIER_HEIGHT), 
 
313
                                             val, NULL);
 
314
 
 
315
    height = (gdouble) self->restrict_area.height * (gdouble) val / 100.0;
 
316
 
 
317
    if (self->area.height != height)
 
318
        self->area.height = height;
 
319
 
 
320
    real = ccm_config_get_integer (ccm_plugin_options_get_config (CCM_PLUGIN_OPTIONS(self), 
 
321
                                                                  CCM_MAGNIFIER_X), 
 
322
                                   &error);
 
323
    if (error)
 
324
    {
 
325
        g_error_free (error);
 
326
        error = NULL;
 
327
        real = -1;
 
328
    }
 
329
    if (real < 0)
 
330
    {
 
331
        self->area.x = (self->restrict_area.width - self->area.width) / 2;
 
332
    }
 
333
    else
 
334
    {
 
335
        val = MAX (0, real);
 
336
        val = MIN (screen->width, val);
 
337
        if (real != val)
 
338
            ccm_config_set_integer (ccm_plugin_options_get_config (CCM_PLUGIN_OPTIONS(self), 
 
339
                                                                   CCM_MAGNIFIER_X), 
 
340
                                    val, NULL);
 
341
 
 
342
        x = val;
 
343
        if (self->area.x != x)
 
344
            self->area.x = x;
 
345
    }
 
346
 
 
347
    real = ccm_config_get_integer (ccm_plugin_options_get_config (CCM_PLUGIN_OPTIONS(self), 
 
348
                                                                  CCM_MAGNIFIER_Y), 
 
349
                                   &error);
 
350
    if (error)
 
351
    {
 
352
        g_error_free (error);
 
353
        error = NULL;
 
354
        real = -1;
 
355
    }
 
356
    if (real < 0)
 
357
    {
 
358
        self->area.y = (self->restrict_area.height - self->area.height) / 2;
 
359
    }
 
360
    else
 
361
    {
 
362
        val = MAX (0, real);
 
363
        val = MIN (screen->height, val);
 
364
        if (real != val)
 
365
            ccm_config_set_integer (ccm_plugin_options_get_config (CCM_PLUGIN_OPTIONS(self), 
 
366
                                                                   CCM_MAGNIFIER_Y), 
 
367
                                    val, NULL);
 
368
 
 
369
        y = val;
 
370
        if (self->area.y != y)
 
371
            self->area.y = y;
 
372
    }
 
373
}
 
374
 
 
375
static void
 
376
ccm_magnifier_options_changed (CCMMagnifierOptions* self, CCMConfig* config)
 
377
{
 
378
    GError *error = NULL;
 
379
 
 
380
    if (config == ccm_plugin_options_get_config(CCM_PLUGIN_OPTIONS(self),
 
381
                                                CCM_MAGNIFIER_ENABLE))
 
382
    {
 
383
        self->enabled = ccm_config_get_boolean(config, NULL);
 
384
    }
 
385
    else if (config == ccm_plugin_options_get_config(CCM_PLUGIN_OPTIONS(self),
 
386
                                                     CCM_MAGNIFIER_ZOOM_LEVEL))
 
387
    {
 
388
        gfloat scale, real = ccm_config_get_float (config, &error);
 
389
 
 
390
        if (error)
 
391
        {
 
392
            g_error_free (error);
 
393
            g_warning ("Error on get magnifier zoom level configuration value");
 
394
            real = 1.5f;
 
395
        }
 
396
        scale = MAX (1.0f, real);
 
397
        scale = MIN (5.0f, scale);
 
398
        if (real != scale) ccm_config_set_float (config, scale, NULL);
 
399
 
 
400
        if (self->new_scale != scale) self->new_scale = scale;
 
401
    }
 
402
    else if (config == ccm_plugin_options_get_config(CCM_PLUGIN_OPTIONS(self),
 
403
                                                     CCM_MAGNIFIER_ZOOM_QUALITY))
 
404
    {
 
405
        gchar *quality = ccm_config_get_string (config, NULL);
 
406
 
 
407
        if (!quality)
 
408
        {
 
409
            if (self->quality != CAIRO_FILTER_FAST)
 
410
            {
 
411
                self->quality = CAIRO_FILTER_FAST;
 
412
                ccm_config_set_string (config, "fast", NULL);
 
413
            }
 
414
        }
 
415
        else
 
416
        {
 
417
            if (!g_ascii_strcasecmp (quality, "fast") && 
 
418
                self->quality != CAIRO_FILTER_FAST)
 
419
            {
 
420
                self->quality = CAIRO_FILTER_FAST;
 
421
            }
 
422
            else if (!g_ascii_strcasecmp (quality, "good") && 
 
423
                     self->quality != CAIRO_FILTER_GOOD)
 
424
            {
 
425
                self->quality = CAIRO_FILTER_GOOD;
 
426
            }
 
427
            else if (!g_ascii_strcasecmp (quality, "best") && 
 
428
                     self->quality != CAIRO_FILTER_BEST)
 
429
            {
 
430
                self->quality = CAIRO_FILTER_BEST;
 
431
            }
 
432
            g_free (quality);
 
433
        }
 
434
    }
 
435
    else if (config == ccm_plugin_options_get_config(CCM_PLUGIN_OPTIONS(self),
 
436
                                                     CCM_MAGNIFIER_SHORTCUT))
 
437
    {
 
438
        if (self->shortcut) g_free(self->shortcut);
 
439
        self->shortcut = ccm_config_get_string (config, &error);
 
440
        if (error)
 
441
        {
 
442
            g_error_free (error);
 
443
            g_warning ("Error on get magnifier shortcut configuration value");
 
444
            self->shortcut = g_strdup ("<Super>F12");
 
445
        }
 
446
    }
 
447
    else if (config == ccm_plugin_options_get_config(CCM_PLUGIN_OPTIONS(self),
 
448
                                                     CCM_MAGNIFIER_SHADE_DESKTOP))
 
449
    {
 
450
        self->shade = ccm_config_get_boolean (config, NULL);
 
451
    }
 
452
    else if (config == ccm_plugin_options_get_config(CCM_PLUGIN_OPTIONS(self),
 
453
                                                     CCM_MAGNIFIER_BORDER))
 
454
    {
 
455
        gint val, real = ccm_config_get_integer (config, NULL);
 
456
 
 
457
        val = MAX (0, real);
 
458
        val = MIN (self->area.width, val);
 
459
        val = MIN (self->area.height, val);
 
460
        if (val != real) ccm_config_set_integer (config, val, NULL);
 
461
 
 
462
        if (self->border != val) self->border = val;
 
463
    }
 
464
    else if (config == ccm_plugin_options_get_config (CCM_PLUGIN_OPTIONS(self),
 
465
                                                      CCM_MAGNIFIER_WIDTH) ||
 
466
             config == ccm_plugin_options_get_config (CCM_PLUGIN_OPTIONS(self),
 
467
                                                      CCM_MAGNIFIER_HEIGHT) ||
 
468
             config == ccm_plugin_options_get_config (CCM_PLUGIN_OPTIONS(self),
 
469
                                                      CCM_MAGNIFIER_X) ||
 
470
             config == ccm_plugin_options_get_config (CCM_PLUGIN_OPTIONS(self),
 
471
                                                      CCM_MAGNIFIER_Y) ||
 
472
             config == ccm_plugin_options_get_config (CCM_PLUGIN_OPTIONS(self),
 
473
                                                      CCM_MAGNIFIER_RESTRICT_AREA_WIDTH) ||
 
474
             config == ccm_plugin_options_get_config (CCM_PLUGIN_OPTIONS(self),
 
475
                                                      CCM_MAGNIFIER_RESTRICT_AREA_HEIGHT) ||
 
476
             config == ccm_plugin_options_get_config (CCM_PLUGIN_OPTIONS(self),
 
477
                                                      CCM_MAGNIFIER_RESTRICT_AREA_X) ||
 
478
             config == ccm_plugin_options_get_config (CCM_PLUGIN_OPTIONS(self),
 
479
                                                      CCM_MAGNIFIER_RESTRICT_AREA_Y))
 
480
    {
 
481
        ccm_magnifier_options_get_restrict_area (self);
 
482
        ccm_magnifier_options_get_size (self);
 
483
    }
 
484
}
 
485
 
 
486
static void
 
487
ccm_magnifier_init (CCMMagnifier * self)
 
488
{
 
489
    self->priv = CCM_MAGNIFIER_GET_PRIVATE (self);
 
490
    self->priv->screen = NULL;
 
491
    self->priv->x_offset = 0;
 
492
    self->priv->y_offset = 0;
 
493
    self->priv->surface = NULL;
 
494
    self->priv->damaged = NULL;
 
495
    self->priv->keybind = NULL;
 
496
 
 
497
    self->priv->surface_window_info = NULL;
 
498
    self->priv->timeline = NULL;
 
499
}
 
500
 
 
501
static void
 
502
ccm_magnifier_finalize (GObject * object)
 
503
{
 
504
    CCMMagnifier *self = CCM_MAGNIFIER (object);
 
505
 
 
506
    if (self->priv->screen)
 
507
        ccm_plugin_options_unload (CCM_PLUGIN (self));
 
508
 
 
509
    if (self->priv->surface)
 
510
        cairo_surface_destroy (self->priv->surface);
 
511
    self->priv->surface = NULL;
 
512
    if (self->priv->damaged)
 
513
        ccm_region_destroy (self->priv->damaged);
 
514
    self->priv->damaged = NULL;
 
515
    if (self->priv->keybind)
 
516
        g_object_unref (self->priv->keybind);
 
517
    self->priv->keybind = NULL;
 
518
    if (self->priv->surface_window_info)
 
519
        cairo_surface_destroy (self->priv->surface_window_info);
 
520
    self->priv->surface_window_info = NULL;
 
521
    if (self->priv->timeline)
 
522
        g_object_unref (self->priv->timeline);
 
523
    self->priv->timeline = NULL;
 
524
 
 
525
    G_OBJECT_CLASS (ccm_magnifier_parent_class)->finalize (object);
 
526
}
 
527
 
 
528
static void
 
529
ccm_magnifier_class_init (CCMMagnifierClass * klass)
 
530
{
 
531
    GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
532
 
 
533
    g_type_class_add_private (klass, sizeof (CCMMagnifierPrivate));
 
534
 
 
535
    object_class->finalize = ccm_magnifier_finalize;
 
536
}
 
537
 
 
538
static void
 
539
ccm_magnifier_set_enable (CCMMagnifier * self, gboolean enabled)
 
540
{
 
541
    if (ccm_magnifier_get_option (self)->enabled != enabled)
 
542
    {
 
543
        ccm_magnifier_get_option (self)->enabled = enabled;
 
544
        if (ccm_magnifier_get_option (self)->enabled)
 
545
        {
 
546
            ccm_screen_manage_cursors (self->priv->screen);
 
547
            if (!self->priv->timeline)
 
548
            {
 
549
                self->priv->timeline = ccm_timeline_new_for_duration (3500);
 
550
                g_object_set (G_OBJECT (self->priv->timeline), "fps", 30, NULL);
 
551
                g_signal_connect_swapped (self->priv->timeline, "new-frame",
 
552
                                          G_CALLBACK
 
553
                                          (ccm_magnifier_on_new_frame), self);
 
554
            }
 
555
            ccm_timeline_rewind (self->priv->timeline);
 
556
            ccm_timeline_start (self->priv->timeline);
 
557
        }
 
558
        else
 
559
        {
 
560
            ccm_screen_unmanage_cursors (self->priv->screen);
 
561
            if (self->priv->surface)
 
562
                cairo_surface_destroy (self->priv->surface);
 
563
            self->priv->surface = NULL;
 
564
            if (self->priv->timeline)
 
565
                ccm_timeline_stop (self->priv->timeline);
 
566
        }
 
567
    }
 
568
}
 
569
 
 
570
static void
 
571
ccm_magnifier_on_key_press (CCMMagnifier * self)
 
572
{
 
573
    g_return_if_fail (self != NULL);
 
574
 
 
575
    int x, y;
 
576
 
 
577
    if (ccm_screen_query_pointer (self->priv->screen, NULL, &x, &y))
 
578
    {
 
579
        gboolean enabled =
 
580
            ccm_config_get_boolean (ccm_magnifier_get_config
 
581
                                    (self, CCM_MAGNIFIER_ENABLE),
 
582
                                    NULL);
 
583
        ccm_config_set_boolean (ccm_magnifier_get_config
 
584
                                (self, CCM_MAGNIFIER_ENABLE), !enabled, NULL);
 
585
        ccm_magnifier_set_enable (self, !enabled);
 
586
        ccm_screen_damage (self->priv->screen);
 
587
    }
 
588
}
 
589
 
 
590
static void
 
591
ccm_magnifier_on_new_frame (CCMMagnifier * self, int num_frame,
 
592
                            CCMTimeline * timeline)
 
593
{
 
594
    gdouble progress = ccm_timeline_get_progress (timeline);
 
595
 
 
596
    if (progress <= 0.25 || progress >= 0.75)
 
597
    {
 
598
        cairo_rectangle_t geometry;
 
599
        CCMRegion *area;
 
600
 
 
601
        geometry.width =
 
602
            ccm_magnifier_get_option (self)->restrict_area.width *
 
603
            (CCM_MAGNIFIER_WINDOW_INFO_WIDTH / 100.f);
 
604
        geometry.height =
 
605
            ccm_magnifier_get_option (self)->restrict_area.height *
 
606
            (CCM_MAGNIFIER_WINDOW_INFO_HEIGHT / 100.f);
 
607
        geometry.x =
 
608
            (ccm_magnifier_get_option (self)->restrict_area.width -
 
609
             geometry.width) / 2;
 
610
        geometry.y = 0;
 
611
 
 
612
        area = ccm_region_rectangle (&geometry);
 
613
        ccm_screen_damage_region (self->priv->screen, area);
 
614
        ccm_region_destroy (area);
 
615
    }
 
616
}
 
617
 
 
618
static void
 
619
ccm_magnifier_get_keybind (CCMMagnifier * self)
 
620
{
 
621
    if (self->priv->keybind)
 
622
        g_object_unref (self->priv->keybind);
 
623
 
 
624
    self->priv->keybind = ccm_keybind_new (self->priv->screen, 
 
625
                                           ccm_magnifier_get_option(self)->shortcut, 
 
626
                                           TRUE);
 
627
 
 
628
    g_signal_connect_swapped (self->priv->keybind, "key_press",
 
629
                              G_CALLBACK (ccm_magnifier_on_key_press), self);
 
630
}
 
631
 
 
632
static void
 
633
ccm_magnifier_get_scale (CCMMagnifier * self)
 
634
{
 
635
    if (ccm_magnifier_get_option(self)->new_scale != ccm_magnifier_get_option(self)->scale)
 
636
    {
 
637
        if (self->priv->timeline
 
638
            && ccm_timeline_is_playing (self->priv->timeline))
 
639
        {
 
640
            gdouble progress = ccm_timeline_get_progress (self->priv->timeline);
 
641
            if (progress > 0.75)
 
642
                ccm_timeline_advance (self->priv->timeline,
 
643
                                      (progress - 0.75) *
 
644
                                      ccm_timeline_get_n_frames (self->priv->timeline));
 
645
        }
 
646
        else if (ccm_magnifier_get_option (self)->enabled)
 
647
        {
 
648
            if (!self->priv->timeline)
 
649
            {
 
650
                self->priv->timeline = ccm_timeline_new_for_duration (3500);
 
651
                g_object_set (G_OBJECT (self->priv->timeline), "fps", 30, NULL);
 
652
                g_signal_connect_swapped (self->priv->timeline, "new-frame",
 
653
                                          G_CALLBACK
 
654
                                          (ccm_magnifier_on_new_frame), self);
 
655
            }
 
656
            ccm_timeline_start (self->priv->timeline);
 
657
            ccm_timeline_rewind (self->priv->timeline);
 
658
        }
 
659
        cairo_surface_destroy (self->priv->surface_window_info);
 
660
        self->priv->surface_window_info = NULL;
 
661
    }
 
662
}
 
663
 
 
664
static void
 
665
ccm_magnifier_create_window_info (CCMMagnifier * self)
 
666
{
 
667
    PangoLayout *layout;
 
668
    PangoFontDescription *desc;
 
669
    cairo_rectangle_t geometry;
 
670
    cairo_t *context;
 
671
    int width, height;
 
672
    char *text;
 
673
    CCMWindow *cow = ccm_screen_get_overlay_window (self->priv->screen);
 
674
    cairo_surface_t *surface = ccm_drawable_get_surface (CCM_DRAWABLE (cow));
 
675
 
 
676
    if (self->priv->surface_window_info)
 
677
        cairo_surface_destroy (self->priv->surface_window_info);
 
678
 
 
679
    self->priv->surface_window_info =
 
680
        cairo_surface_create_similar (surface, CAIRO_CONTENT_COLOR_ALPHA,
 
681
                                      ccm_magnifier_get_option (self)->
 
682
                                      restrict_area.width *
 
683
                                      (CCM_MAGNIFIER_WINDOW_INFO_WIDTH / 100.f),
 
684
                                      ccm_magnifier_get_option (self)->
 
685
                                      restrict_area.height *
 
686
                                      (CCM_MAGNIFIER_WINDOW_INFO_HEIGHT /
 
687
                                       100.f));
 
688
    cairo_surface_destroy (surface);
 
689
    context = cairo_create (self->priv->surface_window_info);
 
690
    cairo_set_operator (context, CAIRO_OPERATOR_CLEAR);
 
691
    cairo_paint (context);
 
692
    cairo_set_operator (context, CAIRO_OPERATOR_SOURCE);
 
693
 
 
694
    geometry.width =
 
695
        ccm_magnifier_get_option (self)->restrict_area.width *
 
696
        (CCM_MAGNIFIER_WINDOW_INFO_WIDTH / 100.f), geometry.height =
 
697
        ccm_magnifier_get_option (self)->restrict_area.height *
 
698
        (CCM_MAGNIFIER_WINDOW_INFO_HEIGHT / 100.f), geometry.x = 0, geometry.y =
 
699
        0;
 
700
 
 
701
    cairo_rectangle_round (context, geometry.x, geometry.y, geometry.width,
 
702
                           geometry.height, 20,
 
703
                           CAIRO_CORNER_BOTTOMLEFT | CAIRO_CORNER_BOTTOMRIGHT);
 
704
    cairo_set_source_rgba (context, 1.0f, 1.0f, 1.0f, 0.8f);
 
705
    cairo_fill_preserve (context);
 
706
    cairo_set_line_width (context, 2.0f);
 
707
    cairo_set_source_rgba (context, 0.f, 0.f, 0.f, 1.0f);
 
708
    cairo_stroke (context);
 
709
 
 
710
    layout = pango_cairo_create_layout (context);
 
711
    text =
 
712
        g_strdup_printf ("Zoom level = %i %%",
 
713
                         (int) (ccm_magnifier_get_option (self)->new_scale *
 
714
                                100));
 
715
    pango_layout_set_text (layout, text, -1);
 
716
    g_free (text);
 
717
    desc = pango_font_description_from_string ("Sans Bold 18");
 
718
    pango_layout_set_font_description (layout, desc);
 
719
    pango_font_description_free (desc);
 
720
    pango_layout_get_pixel_size (layout, &width, &height);
 
721
 
 
722
    cairo_set_source_rgba (context, 0.0f, 0.0f, 0.0f, 1.0f);
 
723
    pango_cairo_update_layout (context, layout);
 
724
    cairo_move_to (context, (geometry.width - width) / 2.0f,
 
725
                   (geometry.height - height) / 2.0f);
 
726
    pango_cairo_show_layout (context, layout);
 
727
    g_object_unref (layout);
 
728
    cairo_destroy (context);
 
729
}
 
730
 
 
731
static void
 
732
ccm_magnifier_paint_window_info (CCMMagnifier * self, cairo_t * context)
 
733
{
 
734
    if (self->priv->timeline && ccm_timeline_is_playing (self->priv->timeline))
 
735
    {
 
736
        if (!self->priv->surface_window_info)
 
737
        {
 
738
            ccm_magnifier_create_window_info (self);
 
739
        }
 
740
 
 
741
        if (self->priv->surface_window_info)
 
742
        {
 
743
            cairo_rectangle_t geometry;
 
744
            gdouble progress = ccm_timeline_get_progress (self->priv->timeline);
 
745
 
 
746
            geometry.width =
 
747
                ccm_magnifier_get_option (self)->restrict_area.width *
 
748
                (CCM_MAGNIFIER_WINDOW_INFO_WIDTH / 100.f);
 
749
            geometry.height =
 
750
                ccm_magnifier_get_option (self)->restrict_area.height *
 
751
                (CCM_MAGNIFIER_WINDOW_INFO_HEIGHT / 100.f);
 
752
            geometry.x =
 
753
                (ccm_magnifier_get_option (self)->restrict_area.width -
 
754
                 geometry.width) / 2;
 
755
            if (progress <= 0.25)
 
756
                geometry.y = -geometry.height * (1 - (progress / 0.25));
 
757
            else if (progress > 0.25 && progress < 0.75)
 
758
                geometry.y = 0;
 
759
            else
 
760
                geometry.y = -geometry.height * ((progress - 0.75) / 0.25);
 
761
 
 
762
            cairo_save (context);
 
763
            cairo_translate (context, geometry.x, geometry.y);
 
764
            cairo_set_source_surface (context, self->priv->surface_window_info,
 
765
                                      0, 0);
 
766
            cairo_paint (context);
 
767
            cairo_restore (context);
 
768
        }
 
769
    }
 
770
}
 
771
 
 
772
static void
 
773
ccm_magnifier_on_option_changed (CCMPlugin * plugin, int index)
 
774
{
 
775
    CCMMagnifier *self = CCM_MAGNIFIER (plugin);
 
776
 
 
777
    switch (index)
 
778
    {
 
779
        case CCM_MAGNIFIER_ENABLE:
 
780
            ccm_screen_damage (self->priv->screen);
 
781
            ccm_magnifier_set_enable (self, 
 
782
                                      ccm_magnifier_get_option(self)->enabled);
 
783
            break;
 
784
        case CCM_MAGNIFIER_ZOOM_LEVEL:
 
785
            ccm_magnifier_get_scale (self);
 
786
            break;
 
787
        case CCM_MAGNIFIER_ZOOM_QUALITY:
 
788
            ccm_screen_damage (self->priv->screen);
 
789
            break;
 
790
        case CCM_MAGNIFIER_SHORTCUT:
 
791
            ccm_magnifier_get_keybind (self);
 
792
            break;
 
793
        case CCM_MAGNIFIER_BORDER:
 
794
            ccm_screen_damage (self->priv->screen);
 
795
            break;
 
796
        case CCM_MAGNIFIER_SHADE_DESKTOP:
 
797
            ccm_screen_damage (self->priv->screen);
 
798
            break;
 
799
        case CCM_MAGNIFIER_X:
 
800
        case CCM_MAGNIFIER_Y:
 
801
        case CCM_MAGNIFIER_WIDTH:
 
802
        case CCM_MAGNIFIER_HEIGHT:
 
803
        case CCM_MAGNIFIER_RESTRICT_AREA_X:
 
804
        case CCM_MAGNIFIER_RESTRICT_AREA_Y:
 
805
        case CCM_MAGNIFIER_RESTRICT_AREA_WIDTH:
 
806
        case CCM_MAGNIFIER_RESTRICT_AREA_HEIGHT:
 
807
            if (self->priv->surface)
 
808
                cairo_surface_destroy (self->priv->surface);
 
809
            self->priv->surface = NULL;
 
810
            ccm_screen_damage (self->priv->screen);
 
811
            break;
 
812
        default:
 
813
            break;
 
814
    }
 
815
}
 
816
 
 
817
static void
 
818
ccm_magnifier_screen_load_options (CCMScreenPlugin * plugin, CCMScreen * screen)
 
819
{
 
820
    CCMMagnifier *self = CCM_MAGNIFIER (plugin);
 
821
 
 
822
    self->priv->screen = screen;
 
823
 
 
824
    ccm_plugin_options_load (CCM_PLUGIN (self), "magnifier",
 
825
                             CCMMagnifierOptionKeys, CCM_MAGNIFIER_OPTION_N,
 
826
                             ccm_magnifier_on_option_changed);
 
827
 
 
828
    ccm_screen_plugin_load_options (CCM_SCREEN_PLUGIN_PARENT (plugin), screen);
 
829
}
 
830
 
 
831
static gboolean
 
832
ccm_magnifier_screen_paint (CCMScreenPlugin * plugin, CCMScreen * screen,
 
833
                            cairo_t * context)
 
834
{
 
835
    CCMMagnifier *self = CCM_MAGNIFIER (plugin);
 
836
 
 
837
    gboolean ret = FALSE;
 
838
 
 
839
    if (ccm_magnifier_get_option (self)->enabled && !self->priv->surface)
 
840
    {
 
841
        CCMWindow *cow = ccm_screen_get_overlay_window (screen);
 
842
        cairo_surface_t *surface =
 
843
            ccm_drawable_get_surface (CCM_DRAWABLE (cow));
 
844
        cairo_t *ctx;
 
845
 
 
846
        self->priv->surface =
 
847
            cairo_surface_create_similar (surface, CAIRO_CONTENT_COLOR,
 
848
                                          ccm_magnifier_get_option (self)->area.width /
 
849
                                          ccm_magnifier_get_option (self)->scale,
 
850
                                          ccm_magnifier_get_option (self)->area.height /
 
851
                                          ccm_magnifier_get_option (self)->scale);
 
852
        cairo_surface_destroy (surface);
 
853
        ctx = cairo_create (self->priv->surface);
 
854
        cairo_set_operator (ctx, CAIRO_OPERATOR_CLEAR);
 
855
        cairo_paint (ctx);
 
856
        cairo_destroy (ctx);
 
857
    }
 
858
 
 
859
    if (ccm_magnifier_get_option (self)->enabled)
 
860
    {
 
861
        CCMRegion *area = ccm_region_rectangle (&ccm_magnifier_get_option (self)->area);
 
862
        cairo_rectangle_t *rects = NULL;
 
863
        CCMRegion *geometry;
 
864
        gint cpt, nb_rects;
 
865
 
 
866
        ccm_debug ("MAGNIFIER PAINT SCREEN CLIP");
 
867
        cairo_save (context);
 
868
 
 
869
        geometry =
 
870
            ccm_region_rectangle (&ccm_magnifier_get_option (self)->
 
871
                                  restrict_area);
 
872
        ccm_region_subtract (geometry, area);
 
873
 
 
874
        ccm_region_get_rectangles (geometry, &rects, &nb_rects);
 
875
        cairo_set_source_rgba (context, 0.0f, 0.0f, 0.0f, 0.6f);
 
876
        for (cpt = 0; cpt < nb_rects; ++cpt)
 
877
            cairo_rectangle (context, rects[cpt].x, rects[cpt].y,
 
878
                             rects[cpt].width, rects[cpt].height);
 
879
        cairo_clip (context);
 
880
        if (rects) cairo_rectangles_free (rects, nb_rects);
 
881
        ccm_region_destroy (area);
 
882
        ccm_region_destroy (geometry);
 
883
 
 
884
        g_object_set (G_OBJECT (self->priv->screen), "buffered_pixmap", FALSE,
 
885
                      NULL);
 
886
        ccm_debug ("MAGNIFIER PAINT SCREEN");
 
887
    }
 
888
 
 
889
    ret =
 
890
        ccm_screen_plugin_paint (CCM_SCREEN_PLUGIN_PARENT (plugin), screen,
 
891
                                 context);
 
892
 
 
893
    if (ccm_magnifier_get_option (self)->enabled)
 
894
        cairo_restore (context);
 
895
 
 
896
    if (ret && ccm_magnifier_get_option (self)->enabled)
 
897
    {
 
898
        CCMRegion *area = ccm_region_rectangle (&ccm_magnifier_get_option (self)->area);
 
899
 
 
900
        ccm_debug ("MAGNIFIER PAINT SCREEN CONTENT");
 
901
 
 
902
        ccm_screen_remove_damaged_region (self->priv->screen, area);
 
903
 
 
904
        if (ccm_magnifier_get_option (self)->shade)
 
905
        {
 
906
            CCMRegion *damaged = ccm_screen_get_damaged (self->priv->screen);
 
907
 
 
908
            if (damaged)
 
909
            {
 
910
                gint cpt, nb_rects;
 
911
                cairo_rectangle_t *rects = NULL;
 
912
 
 
913
                ccm_debug ("MAGNIFIER PAINT SCREEN SHADE");
 
914
 
 
915
                cairo_save (context);
 
916
                cairo_rectangle (context,
 
917
                                 ccm_magnifier_get_option (self)->restrict_area.
 
918
                                 x,
 
919
                                 ccm_magnifier_get_option (self)->restrict_area.
 
920
                                 y,
 
921
                                 ccm_magnifier_get_option (self)->restrict_area.
 
922
                                 width,
 
923
                                 ccm_magnifier_get_option (self)->restrict_area.
 
924
                                 height);
 
925
                cairo_clip (context);
 
926
                ccm_region_get_rectangles (damaged, &rects, &nb_rects);
 
927
                cairo_set_source_rgba (context, 0.0f, 0.0f, 0.0f, 0.6f);
 
928
                for (cpt = 0; cpt < nb_rects; ++cpt)
 
929
                {
 
930
                    cairo_rectangle (context, rects[cpt].x, rects[cpt].y,
 
931
                                     rects[cpt].width, rects[cpt].height);
 
932
                    cairo_fill (context);
 
933
                }
 
934
                if (rects) cairo_rectangles_free (rects, nb_rects);
 
935
                cairo_restore (context);
 
936
 
 
937
                cairo_save (context);
 
938
                cairo_rectangle (context, ccm_magnifier_get_option (self)->area.x - 8,
 
939
                                 ccm_magnifier_get_option (self)->area.y - 8,
 
940
                                 ccm_magnifier_get_option (self)->area.width + 16, 8);
 
941
                cairo_rectangle (context, ccm_magnifier_get_option (self)->area.x - 8,
 
942
                                 ccm_magnifier_get_option (self)->area.y + 
 
943
                                 ccm_magnifier_get_option (self)->area.height,
 
944
                                 ccm_magnifier_get_option (self)->area.width + 16, 8);
 
945
                cairo_rectangle (context, ccm_magnifier_get_option (self)->area.x - 8,
 
946
                                 ccm_magnifier_get_option (self)->area.y - 8, 8,
 
947
                                 ccm_magnifier_get_option (self)->area.height + 16);
 
948
                cairo_rectangle (context,
 
949
                                 ccm_magnifier_get_option (self)->area.x + 
 
950
                                 ccm_magnifier_get_option (self)->area.width,
 
951
                                 ccm_magnifier_get_option (self)->area.y - 8, 8,
 
952
                                 ccm_magnifier_get_option (self)->area.height + 16);
 
953
                cairo_clip (context);
 
954
 
 
955
                cairo_set_source_rgba (context, 1.0f, 1.0f, 1.0f, 0.8f);
 
956
                cairo_rectangle_round (context, ccm_magnifier_get_option (self)->area.x - 8,
 
957
                                       ccm_magnifier_get_option (self)->area.y - 8,
 
958
                                       ccm_magnifier_get_option (self)->area.width + 16,
 
959
                                       ccm_magnifier_get_option (self)->area.height + 16, 10.0f,
 
960
                                       CAIRO_CORNER_ALL);
 
961
                cairo_fill (context);
 
962
                cairo_set_source_rgba (context, 0.0f, 0.0f, 0.0f, 0.9f);
 
963
                cairo_rectangle (context, ccm_magnifier_get_option (self)->area.x - 1,
 
964
                                 ccm_magnifier_get_option (self)->area.y - 1,
 
965
                                 ccm_magnifier_get_option (self)->area.width + 2,
 
966
                                 ccm_magnifier_get_option (self)->area.height + 2);
 
967
                cairo_fill (context);
 
968
                cairo_restore (context);
 
969
 
 
970
                ccm_magnifier_paint_window_info (self, context);
 
971
            }
 
972
        }
 
973
 
 
974
        if (self->priv->damaged)
 
975
        {
 
976
            gint cpt, nb_rects;
 
977
            cairo_rectangle_t *rects = NULL;
 
978
            cairo_pattern_t *pattern;
 
979
 
 
980
            ccm_debug ("MAGNIFIER PAINT SCREEN FILL CONTENT");
 
981
 
 
982
            ccm_screen_add_damaged_region (screen, self->priv->damaged);
 
983
 
 
984
            cairo_save (context);
 
985
 
 
986
            ccm_debug ("MAGNIFIER PAINT SCREEN FILL TRANSLATE SCALE");
 
987
 
 
988
            ccm_region_get_rectangles (self->priv->damaged, &rects, &nb_rects);
 
989
            for (cpt = 0; cpt < nb_rects; ++cpt)
 
990
                cairo_rectangle (context, rects[cpt].x, rects[cpt].y,
 
991
                                 rects[cpt].width, rects[cpt].height);
 
992
            if (rects) cairo_rectangles_free (rects, nb_rects);
 
993
            cairo_clip (context);
 
994
 
 
995
            ccm_debug ("MAGNIFIER PAINT SCREEN FILL CLIP");
 
996
 
 
997
            cairo_translate (context, ccm_magnifier_get_option (self)->area.x, 
 
998
                             ccm_magnifier_get_option (self)->area.y);
 
999
            cairo_scale (context, ccm_magnifier_get_option (self)->scale,
 
1000
                         ccm_magnifier_get_option (self)->scale);
 
1001
            cairo_set_source_surface (context, self->priv->surface, 0, 0);
 
1002
            pattern = cairo_get_source (context);
 
1003
            cairo_pattern_set_filter (pattern,
 
1004
                                      ccm_magnifier_get_option (self)->quality);
 
1005
            cairo_paint (context);
 
1006
 
 
1007
            ccm_debug ("MAGNIFIER PAINT SCREEN FILL PAINT");
 
1008
 
 
1009
            cairo_restore (context);
 
1010
 
 
1011
            ccm_region_destroy (self->priv->damaged);
 
1012
            self->priv->damaged = NULL;
 
1013
        }
 
1014
        ccm_debug ("MAGNIFIER PAINT SCREEN END");
 
1015
 
 
1016
        ccm_region_destroy (area);
 
1017
    }
 
1018
 
 
1019
    if (ccm_magnifier_get_option (self)->scale !=
 
1020
        ccm_magnifier_get_option (self)->new_scale)
 
1021
    {
 
1022
        ccm_magnifier_get_option (self)->scale =
 
1023
            ccm_magnifier_get_option (self)->new_scale;
 
1024
        if (self->priv->surface)
 
1025
            cairo_surface_destroy (self->priv->surface);
 
1026
        self->priv->surface = NULL;
 
1027
    }
 
1028
 
 
1029
    return ret;
 
1030
}
 
1031
 
 
1032
static void
 
1033
ccm_magnifier_screen_on_cursor_move (CCMScreenPlugin * plugin,
 
1034
                                     CCMScreen * screen, int x, int y)
 
1035
{
 
1036
    CCMMagnifier *self = CCM_MAGNIFIER (plugin);
 
1037
 
 
1038
    if (ccm_magnifier_get_option (self)->enabled)
 
1039
    {
 
1040
        CCMDisplay *display = ccm_screen_get_display (screen);
 
1041
        CCMCursor *cursor =
 
1042
            (CCMCursor *) ccm_display_get_current_cursor (display, FALSE);
 
1043
        gboolean damaged = FALSE;
 
1044
 
 
1045
        if (cursor)
 
1046
        {
 
1047
            double width = ccm_cursor_get_width (cursor);
 
1048
            double height = ccm_cursor_get_height (cursor);
 
1049
 
 
1050
            if (self->priv->x_offset >
 
1051
                x - ccm_magnifier_get_option (self)->border)
 
1052
            {
 
1053
                self->priv->x_offset =
 
1054
                    MAX (ccm_magnifier_get_option (self)->restrict_area.x,
 
1055
                         x - ccm_magnifier_get_option (self)->border);
 
1056
                damaged = TRUE;
 
1057
            }
 
1058
            if (self->priv->y_offset >
 
1059
                y - ccm_magnifier_get_option (self)->border)
 
1060
            {
 
1061
                self->priv->y_offset =
 
1062
                    MAX (ccm_magnifier_get_option (self)->restrict_area.y,
 
1063
                         y - ccm_magnifier_get_option (self)->border);
 
1064
                damaged = TRUE;
 
1065
            }
 
1066
            if (self->priv->x_offset +
 
1067
                (ccm_magnifier_get_option (self)->area.width /
 
1068
                 ccm_magnifier_get_option (self)->scale) <
 
1069
                x + width + ccm_magnifier_get_option (self)->border)
 
1070
            {
 
1071
                self->priv->x_offset =
 
1072
                    x + ccm_magnifier_get_option (self)->border + width -
 
1073
                    (ccm_magnifier_get_option (self)->area.width /
 
1074
                     ccm_magnifier_get_option (self)->scale);
 
1075
                if (self->priv->x_offset +
 
1076
                    (ccm_magnifier_get_option (self)->area.width /
 
1077
                     ccm_magnifier_get_option (self)->scale) >
 
1078
                    ccm_magnifier_get_option (self)->restrict_area.width)
 
1079
                    self->priv->x_offset =
 
1080
                    ccm_magnifier_get_option (self)->restrict_area.width -
 
1081
                    (ccm_magnifier_get_option (self)->area.width /
 
1082
                     ccm_magnifier_get_option (self)->scale);
 
1083
                damaged = TRUE;
 
1084
            }
 
1085
            if (self->priv->y_offset +
 
1086
                (ccm_magnifier_get_option (self)->area.height /
 
1087
                 ccm_magnifier_get_option (self)->scale) <
 
1088
                y + height + ccm_magnifier_get_option (self)->border)
 
1089
            {
 
1090
                self->priv->y_offset =
 
1091
                    y + ccm_magnifier_get_option (self)->border + height -
 
1092
                    (ccm_magnifier_get_option (self)->area.height /
 
1093
                     ccm_magnifier_get_option (self)->scale);
 
1094
                if (self->priv->y_offset +
 
1095
                    (ccm_magnifier_get_option (self)->area.height /
 
1096
                     ccm_magnifier_get_option (self)->scale) >
 
1097
                    ccm_magnifier_get_option (self)->restrict_area.height)
 
1098
                    self->priv->y_offset =
 
1099
                    ccm_magnifier_get_option (self)->restrict_area.height -
 
1100
                    (ccm_magnifier_get_option (self)->area.height /
 
1101
                     ccm_magnifier_get_option (self)->scale);
 
1102
                damaged = TRUE;
 
1103
            }
 
1104
        }
 
1105
 
 
1106
        if (damaged)
 
1107
        {
 
1108
            CCMRegion *damage;
 
1109
            cairo_rectangle_t area;
 
1110
 
 
1111
            area.x = self->priv->x_offset;
 
1112
            area.y = self->priv->y_offset;
 
1113
            area.width = ccm_magnifier_get_option (self)->area.width / 
 
1114
                ccm_magnifier_get_option (self)->scale;
 
1115
            area.height = ccm_magnifier_get_option (self)->area.height /
 
1116
                ccm_magnifier_get_option (self)->scale;
 
1117
            damage = ccm_region_rectangle (&area);
 
1118
            ccm_debug ("MAGNIFIER POSITION CHANGED");
 
1119
            ccm_screen_damage_region (self->priv->screen, damage);
 
1120
            ccm_region_destroy (damage);
 
1121
        }
 
1122
    }
 
1123
 
 
1124
    ccm_screen_plugin_on_cursor_move (CCM_SCREEN_PLUGIN_PARENT (plugin), screen,
 
1125
                                      x, y);
 
1126
}
 
1127
 
 
1128
static void
 
1129
ccm_magnifier_screen_paint_cursor (CCMScreenPlugin * plugin, CCMScreen * screen,
 
1130
                                   cairo_t * context, int x, int y)
 
1131
{
 
1132
    CCMMagnifier *self = CCM_MAGNIFIER (plugin);
 
1133
    CCMDisplay *display = ccm_screen_get_display (screen);
 
1134
    CCMCursor *cursor =
 
1135
        (CCMCursor *) ccm_display_get_current_cursor (display, FALSE);
 
1136
 
 
1137
    if (cursor)
 
1138
    {
 
1139
        cairo_save (context);
 
1140
        cairo_translate (context, ccm_magnifier_get_option (self)->area.x, 
 
1141
                         ccm_magnifier_get_option (self)->area.y);
 
1142
        cairo_scale (context, ccm_magnifier_get_option (self)->scale,
 
1143
                     ccm_magnifier_get_option (self)->scale);
 
1144
        ccm_cursor_paint (cursor, context, x - self->priv->x_offset,
 
1145
                          y - self->priv->y_offset);
 
1146
        cairo_restore (context);
 
1147
    }
 
1148
}
 
1149
 
 
1150
static gboolean
 
1151
ccm_magnifier_window_paint (CCMWindowPlugin * plugin, CCMWindow * window,
 
1152
                            cairo_t * context, cairo_surface_t * surface,
 
1153
                            gboolean y_invert)
 
1154
{
 
1155
    CCMScreen *screen = ccm_drawable_get_screen (CCM_DRAWABLE (window));
 
1156
    CCMMagnifier *self = CCM_MAGNIFIER (_ccm_screen_get_plugin (screen,
 
1157
                                                                CCM_TYPE_MAGNIFIER));
 
1158
    if (ccm_magnifier_get_option (self)->enabled)
 
1159
    {
 
1160
        CCMRegion *damaged = (CCMRegion*)
 
1161
            ccm_drawable_get_damaged(CCM_DRAWABLE(window));
 
1162
 
 
1163
        if (damaged)
 
1164
        {
 
1165
            CCMRegion *area = ccm_region_rectangle (&ccm_magnifier_get_option (self)->area);
 
1166
            CCMRegion *tmp = ccm_region_copy (damaged);
 
1167
            cairo_matrix_t matrix;
 
1168
 
 
1169
            cairo_matrix_init_scale (&matrix,
 
1170
                                     ccm_magnifier_get_option (self)->scale,
 
1171
                                     ccm_magnifier_get_option (self)->scale);
 
1172
            cairo_matrix_translate (&matrix, -self->priv->x_offset,
 
1173
                                    -self->priv->y_offset);
 
1174
            ccm_region_transform (tmp, &matrix);
 
1175
            cairo_matrix_init_translate (&matrix, ccm_magnifier_get_option (self)->area.x,
 
1176
                                         ccm_magnifier_get_option (self)->area.y);
 
1177
            ccm_region_transform (tmp, &matrix);
 
1178
            ccm_region_intersect (tmp, area);
 
1179
 
 
1180
            if (!ccm_region_empty (tmp))
 
1181
            {
 
1182
                cairo_t *ctx = cairo_create (self->priv->surface);
 
1183
                cairo_matrix_t translate;
 
1184
 
 
1185
                ccm_debug_window (window, "MAGNIFIER PAINT WINDOW");
 
1186
 
 
1187
                if (!self->priv->damaged)
 
1188
                    self->priv->damaged = ccm_region_copy (tmp);
 
1189
                else
 
1190
                    ccm_region_union (self->priv->damaged, tmp);
 
1191
 
 
1192
                cairo_rectangle (ctx, 0, 0,
 
1193
                                 ccm_magnifier_get_option (self)->area.width /
 
1194
                                 ccm_magnifier_get_option (self)->scale,
 
1195
                                 ccm_magnifier_get_option (self)->area.height /
 
1196
                                 ccm_magnifier_get_option (self)->scale);
 
1197
                cairo_clip (ctx);
 
1198
 
 
1199
                cairo_matrix_init_translate (&translate, -self->priv->x_offset,
 
1200
                                             -self->priv->y_offset);
 
1201
 
 
1202
                cairo_translate (ctx, -self->priv->x_offset, -self->priv->y_offset);
 
1203
                ccm_drawable_get_damage_path (CCM_DRAWABLE (window), ctx);
 
1204
                cairo_clip (ctx);
 
1205
 
 
1206
                ccm_window_set_redirect(window, FALSE);
 
1207
                ccm_drawable_push_matrix (CCM_DRAWABLE (window), "CCMMagnifier",
 
1208
                                          &translate);
 
1209
 
 
1210
                ccm_window_plugin_paint (CCM_WINDOW_PLUGIN_PARENT (plugin), window,
 
1211
                                         ctx, surface, y_invert);
 
1212
                cairo_destroy (ctx);
 
1213
                ccm_drawable_pop_matrix (CCM_DRAWABLE (window), "CCMMagnifier");
 
1214
                ccm_window_set_redirect(window, TRUE);
 
1215
            }
 
1216
 
 
1217
            ccm_region_destroy (tmp);
 
1218
            ccm_region_destroy (area);
 
1219
        }
 
1220
    }
 
1221
 
 
1222
    return ccm_window_plugin_paint (CCM_WINDOW_PLUGIN_PARENT (plugin), window,
 
1223
                                    context, surface, y_invert);
 
1224
}
 
1225
 
 
1226
static void
 
1227
ccm_magnifier_screen_iface_init (CCMScreenPluginClass * iface)
 
1228
{
 
1229
    iface->load_options = ccm_magnifier_screen_load_options;
 
1230
    iface->paint = ccm_magnifier_screen_paint;
 
1231
    iface->add_window = NULL;
 
1232
    iface->remove_window = NULL;
 
1233
    iface->damage = NULL;
 
1234
    iface->on_cursor_move = ccm_magnifier_screen_on_cursor_move;
 
1235
    iface->paint_cursor = ccm_magnifier_screen_paint_cursor;
 
1236
}
 
1237
 
 
1238
static void
 
1239
ccm_magnifier_window_iface_init (CCMWindowPluginClass * iface)
 
1240
{
 
1241
    iface->load_options = NULL;
 
1242
    iface->query_geometry = NULL;
 
1243
    iface->paint = ccm_magnifier_window_paint;
 
1244
    iface->map = NULL;
 
1245
    iface->unmap = NULL;
 
1246
    iface->query_opacity = NULL;
 
1247
    iface->move = NULL;
 
1248
    iface->resize = NULL;
 
1249
    iface->set_opaque_region = NULL;
 
1250
    iface->get_origin = NULL;
 
1251
}