~valavanisalex/ubuntu/oneiric/inkscape/inkscape_0.48.1-2ubuntu4

« back to all changes in this revision

Viewing changes to src/ege-color-prof-tracker.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Kees Cook, Kees Cook, Ted Gould
  • Date: 2008-02-10 14:20:16 UTC
  • mfrom: (1.1.6 upstream)
  • Revision ID: james.westby@ubuntu.com-20080210142016-vcnb2zqyhszu0xvb
Tags: 0.46~pre1-0ubuntu1
[ Kees Cook ]
* debian/control:
  - add libgtkspell-dev build-dep to gain GtkSpell features (LP: #183547).
  - update Standards version (no changes needed).
  - add Vcs and Homepage fields.
  - switch to new python-lxml dep.
* debian/{control,rules}: switch from dpatch to quilt for more sanity.
* debian/patches/20_fix_glib_and_gxx43_ftbfs.patch:
  - merged against upstream fixes.
  - added additional fixes for newly written code.
* debian/rules: enable parallel building.

[ Ted Gould ]
* Updating POTFILES.in to make it so things build correctly.
* debian/control:
  - add ImageMagick++ and libboost-dev to build-deps

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 
2
 *
 
3
 */
 
4
/* ***** BEGIN LICENSE BLOCK *****
 
5
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 
6
 *
 
7
 * The contents of this file are subject to the Mozilla Public License Version
 
8
 * 1.1 (the "License"); you may not use this file except in compliance with
 
9
 * the License. You may obtain a copy of the License at
 
10
 * http://www.mozilla.org/MPL/
 
11
 *
 
12
 * Software distributed under the License is distributed on an "AS IS" basis,
 
13
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 
14
 * for the specific language governing rights and limitations under the
 
15
 * License.
 
16
 *
 
17
 * The Original Code is EGE Color Profile Tracker.
 
18
 *
 
19
 * The Initial Developer of the Original Code is
 
20
 * Jon A. Cruz.
 
21
 * Portions created by the Initial Developer are Copyright (C) 2007
 
22
 * the Initial Developer. All Rights Reserved.
 
23
 *
 
24
 * Contributor(s):
 
25
 *
 
26
 * Alternatively, the contents of this file may be used under the terms of
 
27
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 
28
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 
29
 * in which case the provisions of the GPL or the LGPL are applicable instead
 
30
 * of those above. If you wish to allow use of your version of this file only
 
31
 * under the terms of either the GPL or the LGPL, and not to allow others to
 
32
 * use your version of this file under the terms of the MPL, indicate your
 
33
 * decision by deleting the provisions above and replace them with the notice
 
34
 * and other provisions required by the GPL or the LGPL. If you do not delete
 
35
 * the provisions above, a recipient may use your version of this file under
 
36
 * the terms of any one of the MPL, the GPL or the LGPL.
 
37
 *
 
38
 * ***** END LICENSE BLOCK ***** */
 
39
 
 
40
/* Note: this file should be kept compilable as both .cpp and .c */
 
41
 
 
42
#include <string.h>
 
43
 
 
44
#include <gtk/gtkwidget.h>
 
45
#include <gtk/gtkwindow.h>
 
46
#include <gtk/gtkmarshal.h>
 
47
 
 
48
#ifdef GDK_WINDOWING_X11
 
49
#include <X11/Xlib.h>
 
50
#include <X11/Xatom.h>
 
51
 
 
52
#include <gdk/gdkx.h>
 
53
#endif /* GDK_WINDOWING_X11 */
 
54
 
 
55
#include "ege-color-prof-tracker.h"
 
56
 
 
57
/*
 
58
#define GDK_ROOT_WINDOW()             (gdk_x11_get_default_root_xwindow ())
 
59
#define GDK_DISPLAY()                 gdk_display
 
60
#define             GDK_WINDOW_XDISPLAY(win)
 
61
#define             GDK_WINDOW_XID(win)
 
62
#define             GDK_DISPLAY_XDISPLAY(display)
 
63
#define             GDK_SCREEN_XDISPLAY(screen)
 
64
#define             GDK_SCREEN_XNUMBER(screen)
 
65
#define             GDK_SCREEN_XSCREEN(screen)
 
66
 
 
67
#define             GDK_WINDOW_XWINDOW
 
68
#define             GDK_DRAWABLE_XID(win)
 
69
 
 
70
GdkWindow*          gdk_window_lookup                   (GdkNativeWindow anid);
 
71
GdkWindow*          gdk_window_lookup_for_display       (GdkDisplay *display,
 
72
                                                         GdkNativeWindow anid);
 
73
 
 
74
GdkDisplay*         gdk_x11_lookup_xdisplay             (Display *xdisplay);
 
75
 
 
76
Display*            gdk_x11_display_get_xdisplay        (GdkDisplay *display);
 
77
 
 
78
Window              gdk_x11_get_default_root_xwindow    (void);
 
79
gint                gdk_x11_get_default_screen          (void);
 
80
Display*            gdk_x11_get_default_xdisplay        (void);
 
81
int                 gdk_x11_screen_get_screen_number    (GdkScreen *screen);
 
82
Screen*             gdk_x11_screen_get_xscreen          (GdkScreen *screen);
 
83
 
 
84
const gchar*        gdk_x11_get_xatom_name              (Atom xatom);
 
85
const gchar*        gdk_x11_get_xatom_name_for_display  (GdkDisplay *display,
 
86
                                                         Atom xatom);
 
87
 */
 
88
 
 
89
enum {
 
90
    CHANGED = 0,
 
91
    ADDED,
 
92
    REMOVED,
 
93
    MODIFIED,
 
94
    LAST_SIGNAL};
 
95
 
 
96
 
 
97
static void ege_color_prof_tracker_class_init( EgeColorProfTrackerClass* klass );
 
98
static void ege_color_prof_tracker_init( EgeColorProfTracker* tracker );
 
99
static void ege_color_prof_tracker_get_property( GObject* obj, guint propId, GValue* value, GParamSpec * pspec );
 
100
static void ege_color_prof_tracker_set_property( GObject* obj, guint propId, const GValue *value, GParamSpec* pspec );
 
101
 
 
102
typedef struct _ScreenTrack {
 
103
    GdkScreen* screen;
 
104
#ifdef GDK_WINDOWING_X11
 
105
    gboolean zeroSeen;
 
106
    gboolean otherSeen;
 
107
#endif /* GDK_WINDOWING_X11 */
 
108
    GSList* trackers;
 
109
    GPtrArray* profiles;
 
110
} ScreenTrack;
 
111
 
 
112
#ifdef GDK_WINDOWING_X11
 
113
GdkFilterReturn x11_win_filter(GdkXEvent *xevent, GdkEvent *event, gpointer data);
 
114
void handle_property_change(GdkScreen* screen, const gchar* name);
 
115
void add_x11_tracking_for_screen(GdkScreen* screen, ScreenTrack* screenTrack);
 
116
#endif /* GDK_WINDOWING_X11 */
 
117
 
 
118
static GObjectClass* gParentClass = 0;
 
119
static guint signals[LAST_SIGNAL] = {0};
 
120
 
 
121
static GSList* tracked_screens = 0;
 
122
static GSList* abstract_trackers = 0;
 
123
 
 
124
struct _EgeColorProfTrackerPrivate
 
125
{
 
126
    GtkWidget* _target;
 
127
    gint _monitor;
 
128
};
 
129
 
 
130
#define EGE_GET_PRIVATE( o ) ( G_TYPE_INSTANCE_GET_PRIVATE( (o), EGE_COLOR_PROF_TRACKER_TYPE, EgeColorProfTrackerPrivate ) )
 
131
 
 
132
 
 
133
static void target_finalized( gpointer data, GObject* where_the_object_was );
 
134
static void window_finalized( gpointer data, GObject* where_the_object_was );
 
135
static void event_after_cb( GtkWidget* widget, GdkEvent* event, gpointer user_data );
 
136
static void target_hierarchy_changed_cb(GtkWidget* widget, GtkWidget* prev_top, gpointer user_data);
 
137
static void target_screen_changed_cb(GtkWidget* widget, GdkScreen* prev_screen, gpointer user_data);
 
138
static void screen_size_changed_cb(GdkScreen* screen, gpointer user_data);
 
139
static void fire(GdkScreen* screen, gint monitor);
 
140
static void clear_profile( GdkScreen* screen, guint monitor );
 
141
static void set_profile( GdkScreen* screen, guint monitor, const guint8* data, guint len );
 
142
static void track_screen( GdkScreen* screen, EgeColorProfTracker* tracker );
 
143
 
 
144
GType ege_color_prof_tracker_get_type( void )
 
145
{
 
146
    static GType myType = 0;
 
147
    if ( !myType ) {
 
148
        static const GTypeInfo myInfo = {
 
149
            sizeof( EgeColorProfTrackerClass ),
 
150
            NULL, /* base_init */
 
151
            NULL, /* base_finalize */
 
152
            (GClassInitFunc)ege_color_prof_tracker_class_init,
 
153
            NULL, /* class_finalize */
 
154
            NULL, /* class_data */
 
155
            sizeof( EgeColorProfTracker ),
 
156
            0, /* n_preallocs */
 
157
            (GInstanceInitFunc)ege_color_prof_tracker_init,
 
158
            NULL
 
159
        };
 
160
 
 
161
        myType = g_type_register_static( G_TYPE_OBJECT, "EgeColorProfTracker", &myInfo, (GTypeFlags)0 );
 
162
    }
 
163
 
 
164
    return myType;
 
165
}
 
166
 
 
167
void ege_color_prof_tracker_class_init( EgeColorProfTrackerClass* klass )
 
168
{
 
169
    if ( klass ) {
 
170
        gParentClass = G_OBJECT_CLASS( g_type_class_peek_parent( klass ) );
 
171
        GObjectClass* objClass = G_OBJECT_CLASS( klass );
 
172
 
 
173
        objClass->get_property = ege_color_prof_tracker_get_property;
 
174
        objClass->set_property = ege_color_prof_tracker_set_property;
 
175
        klass->changed = 0;
 
176
 
 
177
        signals[CHANGED] = g_signal_new( "changed",
 
178
                                         G_TYPE_FROM_CLASS(klass),
 
179
                                         G_SIGNAL_RUN_FIRST,
 
180
                                         G_STRUCT_OFFSET(EgeColorProfTrackerClass, changed),
 
181
                                         NULL, NULL,
 
182
                                         g_cclosure_marshal_VOID__VOID,
 
183
                                         G_TYPE_NONE, 0 );
 
184
 
 
185
        signals[ADDED] = g_signal_new( "added",
 
186
                                       G_TYPE_FROM_CLASS(klass),
 
187
                                       G_SIGNAL_RUN_FIRST,
 
188
                                       0,
 
189
                                       NULL, NULL,
 
190
                                       gtk_marshal_VOID__INT_INT,
 
191
                                       G_TYPE_NONE, 2,
 
192
                                       G_TYPE_INT,
 
193
                                       G_TYPE_INT);
 
194
 
 
195
        signals[REMOVED] = g_signal_new( "removed",
 
196
                                         G_TYPE_FROM_CLASS(klass),
 
197
                                         G_SIGNAL_RUN_FIRST,
 
198
                                         0,
 
199
                                         NULL, NULL,
 
200
                                         gtk_marshal_VOID__INT_INT,
 
201
                                         G_TYPE_NONE, 2,
 
202
                                         G_TYPE_INT,
 
203
                                         G_TYPE_INT);
 
204
 
 
205
        signals[MODIFIED] = g_signal_new( "modified",
 
206
                                          G_TYPE_FROM_CLASS(klass),
 
207
                                          G_SIGNAL_RUN_FIRST,
 
208
                                          0,
 
209
                                          NULL, NULL,
 
210
                                          gtk_marshal_VOID__INT_INT,
 
211
                                          G_TYPE_NONE, 2,
 
212
                                          G_TYPE_INT,
 
213
                                          G_TYPE_INT);
 
214
 
 
215
        g_type_class_add_private( klass, sizeof(EgeColorProfTrackerClass) );
 
216
    }
 
217
}
 
218
 
 
219
 
 
220
void ege_color_prof_tracker_init( EgeColorProfTracker* tracker )
 
221
{
 
222
    tracker->private_data = EGE_GET_PRIVATE( tracker );
 
223
    tracker->private_data->_target = 0;
 
224
    tracker->private_data->_monitor = 0;
 
225
}
 
226
 
 
227
EgeColorProfTracker* ege_color_prof_tracker_new( GtkWidget* target )
 
228
{
 
229
    GObject* obj = (GObject*)g_object_new( EGE_COLOR_PROF_TRACKER_TYPE,
 
230
                                           NULL );
 
231
 
 
232
    EgeColorProfTracker* tracker = EGE_COLOR_PROF_TRACKER( obj );
 
233
    tracker->private_data->_target = target;
 
234
 
 
235
    if ( target ) {
 
236
        g_object_weak_ref( G_OBJECT(target), target_finalized, obj );
 
237
        g_signal_connect( G_OBJECT(target), "hierarchy-changed", G_CALLBACK( target_hierarchy_changed_cb ), obj );
 
238
        g_signal_connect( G_OBJECT(target), "screen-changed", G_CALLBACK( target_screen_changed_cb ), obj );
 
239
 
 
240
        /* invoke the callbacks now to connect if the widget is already visible */
 
241
        target_hierarchy_changed_cb( target, 0, obj );
 
242
        target_screen_changed_cb( target, 0, obj );
 
243
    } else {
 
244
        abstract_trackers = g_slist_append( abstract_trackers, obj );
 
245
 
 
246
        GSList* curr = tracked_screens;
 
247
        while ( curr ) {
 
248
            ScreenTrack* track = (ScreenTrack*)curr->data;
 
249
            gint screenNum = gdk_screen_get_number(track->screen);
 
250
            gint monitor = 0;
 
251
            for ( monitor = 0; monitor < (gint)track->profiles->len; monitor++ ) {
 
252
                g_signal_emit( G_OBJECT(tracker), signals[MODIFIED], 0, screenNum, monitor );
 
253
            }
 
254
 
 
255
            curr = g_slist_next(curr);
 
256
        }
 
257
 
 
258
    }
 
259
 
 
260
    return tracker;
 
261
}
 
262
 
 
263
void ege_color_prof_tracker_get_profile( EgeColorProfTracker const * tracker, gpointer* ptr, guint* len )
 
264
{
 
265
    gpointer dataPos = 0;
 
266
    guint dataLen = 0;
 
267
    if ( tracker && tracker->private_data->_target ) {
 
268
        GdkScreen* screen = gtk_widget_get_screen(tracker->private_data->_target);
 
269
        GSList* curr = tracked_screens;
 
270
        while ( curr ) {
 
271
            ScreenTrack* screenTrack = (ScreenTrack*)curr->data;
 
272
            if ( screenTrack->screen == screen ) {
 
273
                if ( tracker->private_data->_monitor >= 0 && tracker->private_data->_monitor < (gint)screenTrack->profiles->len ) {
 
274
                    GByteArray* gba = (GByteArray*)g_ptr_array_index( screenTrack->profiles, tracker->private_data->_monitor );
 
275
                    if ( gba ) {
 
276
                        dataPos = gba->data;
 
277
                        dataLen = gba->len;
 
278
                    }
 
279
                } else {
 
280
                    g_warning("No profile data tracked for the specified item.");
 
281
                }
 
282
                break;
 
283
            }
 
284
            curr = g_slist_next(curr);
 
285
        }
 
286
 
 
287
    }
 
288
    if ( ptr ) {
 
289
        *ptr = dataPos;
 
290
    }
 
291
    if ( len ) {
 
292
        *len = dataLen;
 
293
    }
 
294
}
 
295
 
 
296
void ege_color_prof_tracker_get_profile_for( guint screenNum, guint monitor, gpointer* ptr, guint* len )
 
297
{
 
298
    gpointer dataPos = 0;
 
299
    guint dataLen = 0;
 
300
    GdkDisplay* display = gdk_display_get_default();
 
301
    gint numScreens = gdk_display_get_n_screens(display);
 
302
    GdkScreen* screen = (screenNum < (guint)numScreens) ? gdk_display_get_screen(display, screenNum) : 0;
 
303
 
 
304
    if ( screen ) {
 
305
        GSList* curr = tracked_screens;
 
306
        while ( curr ) {
 
307
            ScreenTrack* screenTrack = (ScreenTrack*)curr->data;
 
308
            if ( screenTrack->screen == screen ) {
 
309
                if ( monitor < screenTrack->profiles->len ) {
 
310
                    GByteArray* gba = (GByteArray*)g_ptr_array_index( screenTrack->profiles, monitor );
 
311
                    if ( gba ) {
 
312
                        dataPos = gba->data;
 
313
                        dataLen = gba->len;
 
314
                    }
 
315
                } else {
 
316
                    g_warning("No profile data tracked for the specified item.");
 
317
                }
 
318
                break;
 
319
            }
 
320
 
 
321
            curr = g_slist_next(curr);
 
322
        }
 
323
    }
 
324
 
 
325
    if ( ptr ) {
 
326
        *ptr = dataPos;
 
327
    }
 
328
    if ( len ) {
 
329
        *len = dataLen;
 
330
    }
 
331
}
 
332
 
 
333
void ege_color_prof_tracker_get_property( GObject* obj, guint propId, GValue* value, GParamSpec * pspec )
 
334
{
 
335
    EgeColorProfTracker* tracker = EGE_COLOR_PROF_TRACKER( obj );
 
336
    (void)tracker;
 
337
    (void)value;
 
338
 
 
339
    switch ( propId ) {
 
340
        default:
 
341
            G_OBJECT_WARN_INVALID_PROPERTY_ID( obj, propId, pspec );
 
342
    }
 
343
}
 
344
 
 
345
void ege_color_prof_tracker_set_property( GObject* obj, guint propId, const GValue *value, GParamSpec* pspec )
 
346
{
 
347
    EgeColorProfTracker* tracker = EGE_COLOR_PROF_TRACKER( obj );
 
348
    (void)tracker;
 
349
    (void)value;
 
350
    switch ( propId ) {
 
351
        default:
 
352
            G_OBJECT_WARN_INVALID_PROPERTY_ID( obj, propId, pspec );
 
353
    }
 
354
}
 
355
 
 
356
 
 
357
void track_screen( GdkScreen* screen, EgeColorProfTracker* tracker )
 
358
{
 
359
    GSList* curr = tracked_screens;
 
360
    /* First remove the tracker from different screens */
 
361
    while ( curr ) {
 
362
        ScreenTrack* screenTrack = (ScreenTrack*)curr->data;
 
363
        if ( screenTrack->screen != screen ) {
 
364
            screenTrack->trackers = g_slist_remove_all(screenTrack->trackers, tracker);
 
365
        }
 
366
        curr = g_slist_next(curr);
 
367
    }
 
368
 
 
369
    curr = tracked_screens;
 
370
    while ( curr && ((ScreenTrack*)curr->data)->screen != screen ) {
 
371
        curr = g_slist_next(curr);
 
372
    }
 
373
 
 
374
    if ( curr ) {
 
375
        /* We found the screen already being tracked */
 
376
        ScreenTrack* screenTrack = (ScreenTrack*)curr->data;
 
377
        GSList* trackHook = g_slist_find( screenTrack->trackers, tracker );
 
378
        if ( !trackHook ) {
 
379
            screenTrack->trackers = g_slist_append( screenTrack->trackers, tracker );
 
380
        }
 
381
    } else {
 
382
        ScreenTrack* newTrack = g_new(ScreenTrack, 1);
 
383
        gint numMonitors = gdk_screen_get_n_monitors(screen);
 
384
        int i = 0;
 
385
        newTrack->screen = screen;
 
386
#ifdef GDK_WINDOWING_X11
 
387
        newTrack->zeroSeen = FALSE;
 
388
        newTrack->otherSeen = FALSE;
 
389
#endif /* GDK_WINDOWING_X11 */
 
390
        newTrack->trackers = g_slist_append( 0, tracker );
 
391
        newTrack->profiles = g_ptr_array_new();
 
392
        for ( i = 0; i < numMonitors; i++ ) {
 
393
            g_ptr_array_add( newTrack->profiles, 0 );
 
394
        }
 
395
        tracked_screens = g_slist_append( tracked_screens, newTrack );
 
396
 
 
397
        g_signal_connect( G_OBJECT(screen), "size-changed", G_CALLBACK( screen_size_changed_cb ), tracker );
 
398
 
 
399
#ifdef GDK_WINDOWING_X11
 
400
        add_x11_tracking_for_screen(screen, newTrack);
 
401
#endif // GDK_WINDOWING_X11
 
402
    }
 
403
}
 
404
 
 
405
 
 
406
void target_finalized( gpointer data, GObject* where_the_object_was )
 
407
{
 
408
    (void)data;
 
409
    GSList* curr = tracked_screens;
 
410
    while ( curr ) {
 
411
        ScreenTrack* track = (ScreenTrack*)curr->data;
 
412
        GSList* trackHook = track->trackers;
 
413
        while ( trackHook ) {
 
414
            if ( (void*)(((EgeColorProfTracker*)(trackHook->data))->private_data->_target) == (void*)where_the_object_was ) {
 
415
                /* The tracked widget is now gone, remove it */
 
416
                ((EgeColorProfTracker*)trackHook->data)->private_data->_target = 0;
 
417
                track->trackers = g_slist_remove( track->trackers, trackHook );
 
418
                trackHook = 0;
 
419
            } else {
 
420
                trackHook = g_slist_next( trackHook );
 
421
            }
 
422
        }
 
423
 
 
424
        curr = g_slist_next( curr );
 
425
    }
 
426
}
 
427
 
 
428
void window_finalized( gpointer data, GObject* where_the_object_was )
 
429
{
 
430
    (void)data;
 
431
    (void)where_the_object_was;
 
432
/*     g_message("Window at %p is now going away", where_the_object_was); */
 
433
}
 
434
 
 
435
void event_after_cb( GtkWidget* widget, GdkEvent* event, gpointer user_data )
 
436
{
 
437
    if ( event->type == GDK_CONFIGURE ) {
 
438
        GdkScreen* screen = gtk_widget_get_screen(widget);
 
439
        GdkWindow* window = widget->window;
 
440
        EgeColorProfTracker* tracker = (EgeColorProfTracker*)user_data;
 
441
        gint monitorNum = gdk_screen_get_monitor_at_window(screen, window);
 
442
        if ( monitorNum != tracker->private_data->_monitor ) {
 
443
            tracker->private_data->_monitor = monitorNum;
 
444
            g_signal_emit( G_OBJECT(tracker), signals[CHANGED], 0 );
 
445
        }
 
446
    }
 
447
}
 
448
 
 
449
void target_hierarchy_changed_cb(GtkWidget* widget, GtkWidget* prev_top, gpointer user_data)
 
450
{
 
451
    if ( !prev_top && gtk_widget_get_toplevel(widget) ) {
 
452
        GtkWidget* top = gtk_widget_get_toplevel(widget);
 
453
        if ( GTK_WIDGET_TOPLEVEL(top) ) {
 
454
            GtkWindow* win = GTK_WINDOW(top);
 
455
            g_signal_connect( G_OBJECT(win), "event-after", G_CALLBACK( event_after_cb ), user_data );
 
456
            g_object_weak_ref( G_OBJECT(win), window_finalized, user_data );
 
457
        }
 
458
    }
 
459
}
 
460
 
 
461
void target_screen_changed_cb(GtkWidget* widget, GdkScreen* prev_screen, gpointer user_data)
 
462
{
 
463
    GdkScreen* screen = gtk_widget_get_screen(widget);
 
464
 
 
465
    if ( screen && (screen != prev_screen) ) {
 
466
        track_screen( screen, EGE_COLOR_PROF_TRACKER(user_data) );
 
467
    }
 
468
}
 
469
 
 
470
void screen_size_changed_cb(GdkScreen* screen, gpointer user_data)
 
471
{
 
472
    GSList* curr = tracked_screens;
 
473
    (void)user_data;
 
474
/*     g_message("screen size changed to (%d, %d) with %d monitors for obj:%p", */
 
475
/*               gdk_screen_get_width(screen), gdk_screen_get_height(screen), */
 
476
/*               gdk_screen_get_n_monitors(screen), */
 
477
/*               user_data); */
 
478
    while ( curr && ((ScreenTrack*)curr->data)->screen != screen ) {
 
479
        curr = g_slist_next(curr);
 
480
    }
 
481
    if ( curr ) {
 
482
        ScreenTrack* track = (ScreenTrack*)curr->data;
 
483
        gint numMonitors = gdk_screen_get_n_monitors(screen);
 
484
        if ( numMonitors > (gint)track->profiles->len ) {
 
485
            guint i = 0;
 
486
            for ( i = track->profiles->len; i < (guint)numMonitors; i++ ) {
 
487
                g_ptr_array_add( track->profiles, 0 );
 
488
#ifdef GDK_WINDOWING_X11
 
489
                {
 
490
                    gchar* name = g_strdup_printf( "_ICC_PROFILE_%d", i );
 
491
                    handle_property_change( screen, name );
 
492
                    g_free(name);
 
493
                }
 
494
#endif /* GDK_WINDOWING_X11 */
 
495
            }
 
496
        } else if ( numMonitors < (gint)track->profiles->len ) {
 
497
/*             g_message("The count of monitors decreased, remove some"); */
 
498
        }
 
499
    }
 
500
}
 
501
 
 
502
void fire(GdkScreen* screen, gint monitor)
 
503
{
 
504
    GSList* curr = tracked_screens;
 
505
    while ( curr ) {
 
506
        ScreenTrack* track = (ScreenTrack*)curr->data;
 
507
        if ( track->screen == screen) {
 
508
            GSList* trackHook = track->trackers;
 
509
            while ( trackHook ) {
 
510
                EgeColorProfTracker* tracker = (EgeColorProfTracker*)(trackHook->data);
 
511
                if ( (monitor == -1) || (tracker->private_data->_monitor == monitor) ) {
 
512
                    g_signal_emit( G_OBJECT(tracker), signals[CHANGED], 0 );
 
513
                }
 
514
                trackHook = g_slist_next(trackHook);
 
515
            }
 
516
        }
 
517
        curr = g_slist_next(curr);
 
518
    }
 
519
}
 
520
 
 
521
static void clear_profile( GdkScreen* screen, guint monitor )
 
522
{
 
523
    GSList* curr = tracked_screens;
 
524
    while ( curr && ((ScreenTrack*)curr->data)->screen != screen ) {
 
525
        curr = g_slist_next(curr);
 
526
    }
 
527
    if ( curr ) {
 
528
        ScreenTrack* track = (ScreenTrack*)curr->data;
 
529
        guint i = 0;
 
530
        GByteArray* previous = 0;
 
531
        for ( i = track->profiles->len; i <= monitor; i++ ) {
 
532
            g_ptr_array_add( track->profiles, 0 );
 
533
        }
 
534
        previous = (GByteArray*)g_ptr_array_index( track->profiles, monitor );
 
535
        if ( previous ) {
 
536
            g_byte_array_free( previous, TRUE );
 
537
        }
 
538
 
 
539
        track->profiles->pdata[monitor] = 0;
 
540
    }
 
541
}
 
542
 
 
543
static void set_profile( GdkScreen* screen, guint monitor, const guint8* data, guint len )
 
544
{
 
545
    GSList* curr = tracked_screens;
 
546
    while ( curr && ((ScreenTrack*)curr->data)->screen != screen ) {
 
547
        curr = g_slist_next(curr);
 
548
    }
 
549
    if ( curr ) {
 
550
        /* Something happened to a screen being tracked. */
 
551
        ScreenTrack* track = (ScreenTrack*)curr->data;
 
552
        gint screenNum = gdk_screen_get_number(screen);
 
553
        guint i = 0;
 
554
        GByteArray* previous = 0;
 
555
        GSList* abstracts = 0;
 
556
 
 
557
        for ( i = track->profiles->len; i <= monitor; i++ ) {
 
558
            g_ptr_array_add( track->profiles, 0 );
 
559
        }
 
560
        previous = (GByteArray*)g_ptr_array_index( track->profiles, monitor );
 
561
        if ( previous ) {
 
562
            g_byte_array_free( previous, TRUE );
 
563
        }
 
564
 
 
565
        if ( data && len ) {
 
566
            GByteArray* newBytes = g_byte_array_sized_new( len );
 
567
            newBytes = g_byte_array_append( newBytes, data, len );
 
568
            track->profiles->pdata[monitor] = newBytes;
 
569
        } else {
 
570
            track->profiles->pdata[monitor] = 0;
 
571
        }
 
572
 
 
573
        for ( abstracts = abstract_trackers; abstracts; abstracts = g_slist_next(abstracts) ) {
 
574
            g_signal_emit( G_OBJECT(abstracts->data), signals[MODIFIED], 0, screenNum, monitor );
 
575
        }
 
576
    }
 
577
}
 
578
 
 
579
#ifdef GDK_WINDOWING_X11
 
580
GdkFilterReturn x11_win_filter(GdkXEvent *xevent,
 
581
                               GdkEvent *event,
 
582
                               gpointer data)
 
583
{
 
584
    XEvent* x11 = (XEvent*)xevent;
 
585
    (void)event;
 
586
    (void)data;
 
587
 
 
588
    if ( x11->type == PropertyNotify ) {
 
589
        XPropertyEvent* note = (XPropertyEvent*)x11;
 
590
        /*GdkAtom gatom = gdk_x11_xatom_to_atom(note->atom);*/
 
591
        const gchar* name = gdk_x11_get_xatom_name(note->atom);
 
592
        if ( strncmp("_ICC_PROFILE", name, 12 ) == 0 ) {
 
593
            XEvent* native = (XEvent*)xevent;
 
594
            Status stat = Success;
 
595
            XWindowAttributes tmp;
 
596
            stat = XGetWindowAttributes( native->xproperty.display, native->xproperty.window, &tmp );
 
597
            if ( stat ) {
 
598
                GdkDisplay* display = gdk_x11_lookup_xdisplay(native->xproperty.display);
 
599
                if ( display ) {
 
600
                    gint screenCount = gdk_display_get_n_screens(display);
 
601
                    GdkScreen* targetScreen = 0;
 
602
                    gint i = 0;
 
603
                    for ( i = 0; i < screenCount; i++ ) {
 
604
                        GdkScreen* sc = gdk_display_get_screen( display, i );
 
605
                        if ( tmp.screen == GDK_SCREEN_XSCREEN(sc) ) {
 
606
                            targetScreen = sc;
 
607
                        }
 
608
                    }
 
609
 
 
610
                    handle_property_change( targetScreen, name );
 
611
                }
 
612
            } else {
 
613
/*                 g_message("%d           failed XGetWindowAttributes with %d", GPOINTER_TO_INT(data), stat); */
 
614
            }
 
615
        }
 
616
    }
 
617
 
 
618
    return GDK_FILTER_CONTINUE;
 
619
}
 
620
 
 
621
void handle_property_change(GdkScreen* screen, const gchar* name)
 
622
{
 
623
    Display* xdisplay = GDK_SCREEN_XDISPLAY(screen);
 
624
    gint monitor = 0;
 
625
    Atom atom = XInternAtom(xdisplay, name, True);
 
626
    if ( strncmp("_ICC_PROFILE_", name, 13 ) == 0 ) {
 
627
        gint64 tmp = g_ascii_strtoll(name + 13, NULL, 10);
 
628
        if ( tmp != 0 && tmp != G_MAXINT64 && tmp != G_MININT64 ) {
 
629
            monitor = (gint)tmp;
 
630
        }
 
631
    }
 
632
    if ( atom != None ) {
 
633
        Atom actualType = None;
 
634
        int actualFormat = 0;
 
635
        unsigned long size = 128 * 1042;
 
636
        unsigned long nitems = 0;
 
637
        unsigned long bytesAfter = 0;
 
638
        unsigned char* prop = 0;
 
639
 
 
640
        clear_profile( screen, monitor );
 
641
 
 
642
        if ( XGetWindowProperty( xdisplay, GDK_WINDOW_XID(gdk_screen_get_root_window(screen)),
 
643
                                 atom, 0, size, False, AnyPropertyType,
 
644
                                 &actualType, &actualFormat, &nitems, &bytesAfter, &prop ) == Success ) {
 
645
            if ( (actualType != None) && (bytesAfter + nitems) ) {
 
646
                size = nitems + bytesAfter;
 
647
                bytesAfter = 0;
 
648
                nitems = 0;
 
649
                if ( prop ) {
 
650
                    XFree(prop);
 
651
                    prop = 0;
 
652
                }
 
653
                if ( XGetWindowProperty( xdisplay, GDK_WINDOW_XID(gdk_screen_get_root_window(screen)),
 
654
                                         atom, 0, size, False, AnyPropertyType,
 
655
                                         &actualType, &actualFormat, &nitems, &bytesAfter, &prop ) == Success ) {
 
656
                    gpointer profile = g_memdup( prop, nitems );
 
657
                    set_profile( screen, monitor, (const guint8*)profile, nitems );
 
658
                    XFree(prop);
 
659
                } else {
 
660
                    g_warning("Problem reading profile from root window");
 
661
                }
 
662
            } else {
 
663
                /* clear it */
 
664
                set_profile( screen, monitor, 0, 0 );
 
665
            }
 
666
        } else {
 
667
            g_warning("error loading profile property");
 
668
        }
 
669
    }
 
670
    fire(screen, monitor);
 
671
}
 
672
 
 
673
void add_x11_tracking_for_screen(GdkScreen* screen, ScreenTrack* screenTrack)
 
674
{
 
675
    Display* xdisplay = GDK_SCREEN_XDISPLAY(screen);
 
676
    GdkWindow* root = gdk_screen_get_root_window(screen);
 
677
    if ( root ) {
 
678
        Window rootWin = GDK_WINDOW_XID(root);
 
679
        Atom baseAtom = XInternAtom(xdisplay, "_ICC_PROFILE", True);
 
680
        int numWinProps = 0;
 
681
        Atom* propArray = XListProperties(xdisplay, rootWin, &numWinProps);
 
682
        gint i;
 
683
 
 
684
        gdk_window_set_events(root, (GdkEventMask)(gdk_window_get_events(root) | GDK_PROPERTY_CHANGE_MASK));
 
685
        gdk_window_add_filter(root, x11_win_filter, GINT_TO_POINTER(1));
 
686
 
 
687
        /* Look for any profiles attached to this root window */
 
688
        if ( propArray ) {
 
689
            int j = 0;
 
690
            gint numMonitors = gdk_screen_get_n_monitors(screen);
 
691
 
 
692
            if ( baseAtom != None ) {
 
693
                for ( i = 0; i < numWinProps; i++ ) {
 
694
                    if ( baseAtom == propArray[i] ) {
 
695
                        screenTrack->zeroSeen = TRUE;
 
696
                        handle_property_change( screen, "_ICC_PROFILE" );
 
697
                    }
 
698
                }
 
699
            } else {
 
700
/*                 g_message("Base atom not found"); */
 
701
            }
 
702
 
 
703
            for ( i = 1; i < numMonitors; i++ ) {
 
704
                gchar* name = g_strdup_printf("_ICC_PROFILE_%d", i);
 
705
                Atom atom = XInternAtom(xdisplay, name, True);
 
706
                if ( atom != None ) {
 
707
                    for ( j = 0; j < numWinProps; j++ ) {
 
708
                        if ( atom == propArray[j] ) {
 
709
                            screenTrack->otherSeen = TRUE;
 
710
                            handle_property_change( screen, name );
 
711
                        }
 
712
                    }
 
713
                }
 
714
                g_free(name);
 
715
            }
 
716
            XFree(propArray);
 
717
            propArray = 0;
 
718
        }
 
719
    }
 
720
}
 
721
#endif /* GDK_WINDOWING_X11 */