From: joncruz Date: Sat, 17 Nov 2007 08:56:33 +0000 (+0000) Subject: Adding ICC Profiles in X support X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=2946d610c3b90ab57cbf8b08c25e43111a7b5ebd;p=inkscape.git Adding ICC Profiles in X support --- diff --git a/src/Makefile_insert b/src/Makefile_insert index 823449890..3d5d2e55a 100644 --- a/src/Makefile_insert +++ b/src/Makefile_insert @@ -289,6 +289,8 @@ libinkpost_a_SOURCES = \ dir-util.cpp dir-util.h \ ege-adjustment-action.cpp \ ege-adjustment-action.h \ + ege-color-prof-tracker.cpp \ + ege-color-prof-tracker.h \ ege-output-action.cpp \ ege-output-action.h \ ege-select-one-action.cpp \ diff --git a/src/ege-color-prof-tracker.cpp b/src/ege-color-prof-tracker.cpp new file mode 100644 index 000000000..2496b8dd6 --- /dev/null +++ b/src/ege-color-prof-tracker.cpp @@ -0,0 +1,619 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is EGE Color Profile Tracker. + * + * The Initial Developer of the Original Code is + * Jon A. Cruz. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* Note: this file should be kept compilable as both .cpp and .c */ + +#include + +#include +#include + +#ifdef GDK_WINDOWING_X11 +#include +#include + +#include +#endif /* GDK_WINDOWING_X11 */ + +#include "ege-color-prof-tracker.h" + +/* +#define GDK_ROOT_WINDOW() (gdk_x11_get_default_root_xwindow ()) +#define GDK_DISPLAY() gdk_display +#define GDK_WINDOW_XDISPLAY(win) +#define GDK_WINDOW_XID(win) +#define GDK_DISPLAY_XDISPLAY(display) +#define GDK_SCREEN_XDISPLAY(screen) +#define GDK_SCREEN_XNUMBER(screen) +#define GDK_SCREEN_XSCREEN(screen) + +#define GDK_WINDOW_XWINDOW +#define GDK_DRAWABLE_XID(win) + +GdkWindow* gdk_window_lookup (GdkNativeWindow anid); +GdkWindow* gdk_window_lookup_for_display (GdkDisplay *display, + GdkNativeWindow anid); + +GdkDisplay* gdk_x11_lookup_xdisplay (Display *xdisplay); + +Display* gdk_x11_display_get_xdisplay (GdkDisplay *display); + +Window gdk_x11_get_default_root_xwindow (void); +gint gdk_x11_get_default_screen (void); +Display* gdk_x11_get_default_xdisplay (void); +int gdk_x11_screen_get_screen_number (GdkScreen *screen); +Screen* gdk_x11_screen_get_xscreen (GdkScreen *screen); + +const gchar* gdk_x11_get_xatom_name (Atom xatom); +const gchar* gdk_x11_get_xatom_name_for_display (GdkDisplay *display, + Atom xatom); + */ + +enum { + CHANGED = 0, + LAST_SIGNAL}; + + +static void ege_color_prof_tracker_class_init( EgeColorProfTrackerClass* klass ); +static void ege_color_prof_tracker_init( EgeColorProfTracker* tracker ); +static void ege_color_prof_tracker_get_property( GObject* obj, guint propId, GValue* value, GParamSpec * pspec ); +static void ege_color_prof_tracker_set_property( GObject* obj, guint propId, const GValue *value, GParamSpec* pspec ); + +typedef struct _ScreenTrack { + GdkScreen* screen; +#ifdef GDK_WINDOWING_X11 + gboolean zeroSeen; + gboolean otherSeen; +#endif /* GDK_WINDOWING_X11 */ + GSList* trackers; + GPtrArray* profiles; +} ScreenTrack; + +#ifdef GDK_WINDOWING_X11 +GdkFilterReturn x11_win_filter(GdkXEvent *xevent, GdkEvent *event, gpointer data); +void handle_property_change(GdkScreen* screen, const gchar* name); +void add_x11_tracking_for_screen(GdkScreen* screen, ScreenTrack* screenTrack); +#endif /* GDK_WINDOWING_X11 */ + +static GObjectClass* gParentClass = 0; +static guint signals[LAST_SIGNAL] = {0}; + +static GSList* tracked_screens = 0; + + +struct _EgeColorProfTrackerPrivate +{ + GtkWidget* _target; + gint _monitor; +}; + +#define EGE_GET_PRIVATE( o ) ( G_TYPE_INSTANCE_GET_PRIVATE( (o), EGE_COLOR_PROF_TRACKER_TYPE, EgeColorProfTrackerPrivate ) ) + + +static void target_finalized( gpointer data, GObject* where_the_object_was ); +static void window_finalized( gpointer data, GObject* where_the_object_was ); +static void event_after_cb( GtkWidget* widget, GdkEvent* event, gpointer user_data ); +static void target_hierarchy_changed_cb(GtkWidget* widget, GtkWidget* prev_top, gpointer user_data); +static void target_screen_changed_cb(GtkWidget* widget, GdkScreen* prev_screen, gpointer user_data); +static void screen_size_changed_cb(GdkScreen* screen, gpointer user_data); +static void fire(GdkScreen* screen, gint monitor); +static void clear_profile( GdkScreen* screen, guint monitor ); +static void set_profile( GdkScreen* screen, guint monitor, const guint8* data, guint len ); + +GType ege_color_prof_tracker_get_type( void ) +{ + static GType myType = 0; + if ( !myType ) { + static const GTypeInfo myInfo = { + sizeof( EgeColorProfTrackerClass ), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc)ege_color_prof_tracker_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof( EgeColorProfTracker ), + 0, /* n_preallocs */ + (GInstanceInitFunc)ege_color_prof_tracker_init, + NULL + }; + + myType = g_type_register_static( G_TYPE_OBJECT, "EgeColorProfTracker", &myInfo, (GTypeFlags)0 ); + } + + return myType; +} + +void ege_color_prof_tracker_class_init( EgeColorProfTrackerClass* klass ) +{ + if ( klass ) { + gParentClass = G_OBJECT_CLASS( g_type_class_peek_parent( klass ) ); + GObjectClass* objClass = G_OBJECT_CLASS( klass ); + + objClass->get_property = ege_color_prof_tracker_get_property; + objClass->set_property = ege_color_prof_tracker_set_property; + + signals[CHANGED] = g_signal_new( "changed", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET(EgeColorProfTrackerClass, changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + g_type_class_add_private( klass, sizeof(EgeColorProfTrackerClass) ); + } +} + + +void ege_color_prof_tracker_init( EgeColorProfTracker* tracker ) +{ + tracker->private_data = EGE_GET_PRIVATE( tracker ); + tracker->private_data->_target = 0; + tracker->private_data->_monitor = 0; +} + +EgeColorProfTracker* ege_color_prof_tracker_new( GtkWidget* target ) +{ + GObject* obj = (GObject*)g_object_new( EGE_COLOR_PROF_TRACKER_TYPE, + NULL ); + + EgeColorProfTracker* tracker = EGE_COLOR_PROF_TRACKER( obj ); + tracker->private_data->_target = target; + + g_object_weak_ref( G_OBJECT(target), target_finalized, obj ); + g_signal_connect( G_OBJECT(target), "hierarchy-changed", G_CALLBACK( target_hierarchy_changed_cb ), obj ); + g_signal_connect( G_OBJECT(target), "screen-changed", G_CALLBACK( target_screen_changed_cb ), obj ); + + /* invoke the callbacks now to connect if the widget is already visible */ + target_hierarchy_changed_cb( target, 0, obj ); + target_screen_changed_cb( target, 0, obj ); + + return tracker; +} + +void ege_color_prof_tracker_get_profile( EgeColorProfTracker const * tracker, gpointer* ptr, guint* len ) +{ + gpointer dataPos = 0; + guint dataLen = 0; + if ( tracker && tracker->private_data->_target ) { + GdkScreen* screen = gtk_widget_get_screen(tracker->private_data->_target); + GSList* curr = tracked_screens; + while ( curr ) { + ScreenTrack* screenTrack = (ScreenTrack*)curr->data; + if ( screenTrack->screen == screen ) { + if ( tracker->private_data->_monitor >= 0 && tracker->private_data->_monitor < (gint)screenTrack->profiles->len ) { + GByteArray* gba = (GByteArray*)g_ptr_array_index( screenTrack->profiles, tracker->private_data->_monitor ); + if ( gba ) { + dataPos = gba->data; + dataLen = gba->len; + } + } else { + g_warning("No profile data tracked for the specified item."); + } + break; + } + curr = g_slist_next(curr); + } + + } + if ( ptr ) { + *ptr = dataPos; + } + if ( len ) { + *len = dataLen; + } +} + +void ege_color_prof_tracker_get_property( GObject* obj, guint propId, GValue* value, GParamSpec * pspec ) +{ + EgeColorProfTracker* tracker = EGE_COLOR_PROF_TRACKER( obj ); + (void)tracker; + (void)value; + + switch ( propId ) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID( obj, propId, pspec ); + } +} + +void ege_color_prof_tracker_set_property( GObject* obj, guint propId, const GValue *value, GParamSpec* pspec ) +{ + EgeColorProfTracker* tracker = EGE_COLOR_PROF_TRACKER( obj ); + (void)tracker; + (void)value; + switch ( propId ) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID( obj, propId, pspec ); + } +} + + +static void track_screen( GdkScreen* screen, EgeColorProfTracker* tracker ) +{ + GSList* curr = tracked_screens; + /* First remove the tracker from different screens */ + while ( curr ) { + ScreenTrack* screenTrack = (ScreenTrack*)curr->data; + if ( screenTrack->screen != screen ) { + screenTrack->trackers = g_slist_remove_all(screenTrack->trackers, tracker); + } + curr = g_slist_next(curr); + } + + curr = tracked_screens; + while ( curr && ((ScreenTrack*)curr->data)->screen != screen ) { + curr = g_slist_next(curr); + } + + if ( curr ) { + /* We found the screen already being tracked */ + ScreenTrack* screenTrack = (ScreenTrack*)curr->data; + GSList* trackHook = g_slist_find( screenTrack->trackers, tracker ); + if ( !trackHook ) { + screenTrack->trackers = g_slist_append( screenTrack->trackers, tracker ); + } + } else { + ScreenTrack* newTrack = g_new(ScreenTrack, 1); + gint numMonitors = gdk_screen_get_n_monitors(screen); + int i = 0; + newTrack->screen = screen; +#ifdef GDK_WINDOWING_X11 + newTrack->zeroSeen = FALSE; + newTrack->otherSeen = FALSE; +#endif /* GDK_WINDOWING_X11 */ + newTrack->trackers = g_slist_append( 0, tracker ); + newTrack->profiles = g_ptr_array_new(); + for ( i = 0; i < numMonitors; i++ ) { + g_ptr_array_add( newTrack->profiles, 0 ); + } + tracked_screens = g_slist_append( tracked_screens, newTrack ); + + g_signal_connect( G_OBJECT(screen), "size-changed", G_CALLBACK( screen_size_changed_cb ), tracker ); + +#ifdef GDK_WINDOWING_X11 + add_x11_tracking_for_screen(screen, newTrack); +#endif // GDK_WINDOWING_X11 + } +} + + +void target_finalized( gpointer data, GObject* where_the_object_was ) +{ + (void)data; + GSList* curr = tracked_screens; + while ( curr ) { + ScreenTrack* track = (ScreenTrack*)curr->data; + GSList* trackHook = track->trackers; + while ( trackHook ) { + if ( (void*)(((EgeColorProfTracker*)(trackHook->data))->private_data->_target) == (void*)where_the_object_was ) { + /* The tracked widget is now gone, remove it */ + ((EgeColorProfTracker*)trackHook->data)->private_data->_target = 0; + track->trackers = g_slist_remove( track->trackers, trackHook ); + trackHook = 0; + } else { + trackHook = g_slist_next( trackHook ); + } + } + + curr = g_slist_next( curr ); + } +} + +void window_finalized( gpointer data, GObject* where_the_object_was ) +{ + (void)data; + (void)where_the_object_was; +/* g_message("Window at %p is now going away", where_the_object_was); */ +} + +void event_after_cb( GtkWidget* widget, GdkEvent* event, gpointer user_data ) +{ + if ( event->type == GDK_CONFIGURE ) { + GdkScreen* screen = gtk_widget_get_screen(widget); + GdkWindow* window = widget->window; + EgeColorProfTracker* tracker = (EgeColorProfTracker*)user_data; + gint monitorNum = gdk_screen_get_monitor_at_window(screen, window); + if ( monitorNum != tracker->private_data->_monitor ) { + tracker->private_data->_monitor = monitorNum; + g_signal_emit( G_OBJECT(tracker), signals[CHANGED], 0 ); + } + } +} + +void target_hierarchy_changed_cb(GtkWidget* widget, GtkWidget* prev_top, gpointer user_data) +{ + if ( !prev_top && gtk_widget_get_toplevel(widget) ) { + GtkWidget* top = gtk_widget_get_toplevel(widget); + if ( GTK_WIDGET_TOPLEVEL(top) ) { + GtkWindow* win = GTK_WINDOW(top); + g_signal_connect( G_OBJECT(win), "event-after", G_CALLBACK( event_after_cb ), user_data ); + g_object_weak_ref( G_OBJECT(win), window_finalized, user_data ); + } + } +} + +void target_screen_changed_cb(GtkWidget* widget, GdkScreen* prev_screen, gpointer user_data) +{ + GdkScreen* screen = gtk_widget_get_screen(widget); + + if ( screen && (screen != prev_screen) ) { + track_screen( screen, EGE_COLOR_PROF_TRACKER(user_data) ); + } +} + +void screen_size_changed_cb(GdkScreen* screen, gpointer user_data) +{ + GSList* curr = tracked_screens; + (void)user_data; +/* g_message("screen size changed to (%d, %d) with %d monitors for obj:%p", */ +/* gdk_screen_get_width(screen), gdk_screen_get_height(screen), */ +/* gdk_screen_get_n_monitors(screen), */ +/* user_data); */ + while ( curr && ((ScreenTrack*)curr->data)->screen != screen ) { + curr = g_slist_next(curr); + } + if ( curr ) { + ScreenTrack* track = (ScreenTrack*)curr->data; + gint numMonitors = gdk_screen_get_n_monitors(screen); + if ( numMonitors > (gint)track->profiles->len ) { + guint i = 0; + for ( i = track->profiles->len; i < (guint)numMonitors; i++ ) { + g_ptr_array_add( track->profiles, 0 ); +#ifdef GDK_WINDOWING_X11 + { + gchar* name = g_strdup_printf( "_ICC_PROFILE_%d", i ); + handle_property_change( screen, name ); + g_free(name); + } +#endif /* GDK_WINDOWING_X11 */ + } + } else if ( numMonitors < (gint)track->profiles->len ) { +/* g_message("The count of monitors decreased, remove some"); */ + } + } +} + +void fire(GdkScreen* screen, gint monitor) +{ + GSList* curr = tracked_screens; + while ( curr ) { + ScreenTrack* track = (ScreenTrack*)curr->data; + if ( track->screen == screen) { + GSList* trackHook = track->trackers; + while ( trackHook ) { + EgeColorProfTracker* tracker = (EgeColorProfTracker*)(trackHook->data); + if ( (monitor == -1) || (tracker->private_data->_monitor == monitor) ) { + g_signal_emit( G_OBJECT(tracker), signals[CHANGED], 0 ); + } + trackHook = g_slist_next(trackHook); + } + } + curr = g_slist_next(curr); + } +} + +static void clear_profile( GdkScreen* screen, guint monitor ) +{ + GSList* curr = tracked_screens; + while ( curr && ((ScreenTrack*)curr->data)->screen != screen ) { + curr = g_slist_next(curr); + } + if ( curr ) { + ScreenTrack* track = (ScreenTrack*)curr->data; + guint i = 0; + GByteArray* previous = 0; + for ( i = track->profiles->len; i <= monitor; i++ ) { + g_ptr_array_add( track->profiles, 0 ); + } + previous = (GByteArray*)g_ptr_array_index( track->profiles, monitor ); + if ( previous ) { + g_byte_array_free( previous, TRUE ); + } + + track->profiles->pdata[monitor] = 0; + } +} + +static void set_profile( GdkScreen* screen, guint monitor, const guint8* data, guint len ) +{ + GSList* curr = tracked_screens; + while ( curr && ((ScreenTrack*)curr->data)->screen != screen ) { + curr = g_slist_next(curr); + } + if ( curr ) { + ScreenTrack* track = (ScreenTrack*)curr->data; + guint i = 0; + GByteArray* previous = 0; + for ( i = track->profiles->len; i <= monitor; i++ ) { + g_ptr_array_add( track->profiles, 0 ); + } + previous = (GByteArray*)g_ptr_array_index( track->profiles, monitor ); + if ( previous ) { + g_byte_array_free( previous, TRUE ); + } + + if ( data && len ) { + GByteArray* newBytes = g_byte_array_sized_new( len ); + newBytes = g_byte_array_append( newBytes, data, len ); + track->profiles->pdata[monitor] = newBytes; + } else { + track->profiles->pdata[monitor] = 0; + } + } +} + +#ifdef GDK_WINDOWING_X11 +GdkFilterReturn x11_win_filter(GdkXEvent *xevent, + GdkEvent *event, + gpointer data) +{ + XEvent* x11 = (XEvent*)xevent; + (void)event; + (void)data; + + if ( x11->type == PropertyNotify ) { + XPropertyEvent* note = (XPropertyEvent*)x11; + /*GdkAtom gatom = gdk_x11_xatom_to_atom(note->atom);*/ + const gchar* name = gdk_x11_get_xatom_name(note->atom); + if ( strncmp("_ICC_PROFILE", name, 12 ) == 0 ) { + XEvent* native = (XEvent*)xevent; + Status stat = Success; + XWindowAttributes tmp; + stat = XGetWindowAttributes( native->xproperty.display, native->xproperty.window, &tmp ); + if ( stat ) { + GdkDisplay* display = gdk_x11_lookup_xdisplay(native->xproperty.display); + if ( display ) { + gint screenCount = gdk_display_get_n_screens(display); + GdkScreen* targetScreen = 0; + gint i = 0; + for ( i = 0; i < screenCount; i++ ) { + GdkScreen* sc = gdk_display_get_screen( display, i ); + if ( tmp.screen == GDK_SCREEN_XSCREEN(sc) ) { + targetScreen = sc; + } + } + + handle_property_change( targetScreen, name ); + } + } else { +/* g_message("%d failed XGetWindowAttributes with %d", GPOINTER_TO_INT(data), stat); */ + } + } + } + + return GDK_FILTER_CONTINUE; +} + +void handle_property_change(GdkScreen* screen, const gchar* name) +{ + Display* xdisplay = GDK_SCREEN_XDISPLAY(screen); + gint monitor = 0; + Atom atom = XInternAtom(xdisplay, name, True); + if ( strncmp("_ICC_PROFILE_", name, 13 ) == 0 ) { + gint64 tmp = g_ascii_strtoll(name + 13, NULL, 10); + if ( tmp != 0 && tmp != G_MAXINT64 && tmp != G_MININT64 ) { + monitor = (gint)tmp; + } + } + if ( atom != None ) { + Atom actualType = None; + int actualFormat = 0; + unsigned long size = 128 * 1042; + unsigned long nitems = 0; + unsigned long bytesAfter = 0; + unsigned char* prop = 0; + + clear_profile( screen, monitor ); + + if ( XGetWindowProperty( xdisplay, GDK_WINDOW_XID(gdk_screen_get_root_window(screen)), + atom, 0, size, False, AnyPropertyType, + &actualType, &actualFormat, &nitems, &bytesAfter, &prop ) == Success ) { + if ( (actualType != None) && (bytesAfter + nitems) ) { + size = nitems + bytesAfter; + bytesAfter = 0; + nitems = 0; + if ( XGetWindowProperty( xdisplay, GDK_WINDOW_XID(gdk_screen_get_root_window(screen)), + atom, 0, size, False, AnyPropertyType, + &actualType, &actualFormat, &nitems, &bytesAfter, &prop ) == Success ) { + gpointer profile = g_memdup( prop, nitems ); + set_profile( screen, monitor, (const guint8*)profile, nitems ); + XFree(prop); + } else { + g_warning("Problem reading profile from root window"); + } + } else { + /* clear it */ + set_profile( screen, monitor, 0, 0 ); + } + } else { + g_message("error loading profile property"); + } + } + fire(screen, monitor); +} + +void add_x11_tracking_for_screen(GdkScreen* screen, ScreenTrack* screenTrack) +{ + Display* xdisplay = GDK_SCREEN_XDISPLAY(screen); + GdkWindow* root = gdk_screen_get_root_window(screen); + if ( root ) { + Window rootWin = GDK_WINDOW_XID(root); + Atom baseAtom = XInternAtom(xdisplay, "_ICC_PROFILE", True); + int numWinProps = 0; + Atom* propArray = XListProperties(xdisplay, rootWin, &numWinProps); + gint i; + + gdk_window_set_events(root, (GdkEventMask)(gdk_window_get_events(root) | GDK_PROPERTY_CHANGE_MASK)); + gdk_window_add_filter(root, x11_win_filter, GINT_TO_POINTER(1)); + + /* Look for any profiles attached to this root window */ + if ( propArray ) { + int j = 0; + gint numMonitors = gdk_screen_get_n_monitors(screen); + + if ( baseAtom != None ) { + for ( i = 0; i < numWinProps; i++ ) { + if ( baseAtom == propArray[i] ) { + screenTrack->zeroSeen = TRUE; + handle_property_change( screen, "_ICC_PROFILE" ); + } + } + } else { +/* g_message("Base atom not found"); */ + } + + for ( i = 1; i < numMonitors; i++ ) { + gchar* name = g_strdup_printf("_ICC_PROFILE_%d", i); + Atom atom = XInternAtom(xdisplay, name, True); + if ( atom != None ) { + for ( j = 0; j < numWinProps; j++ ) { + if ( atom == propArray[j] ) { + screenTrack->otherSeen = TRUE; + handle_property_change( screen, name ); + } + } + } + g_free(name); + } + XFree(propArray); + propArray = 0; + } + } +} +#endif /* GDK_WINDOWING_X11 */ diff --git a/src/ege-color-prof-tracker.h b/src/ege-color-prof-tracker.h new file mode 100644 index 000000000..69a3112fb --- /dev/null +++ b/src/ege-color-prof-tracker.h @@ -0,0 +1,104 @@ +#ifndef SEEN_EGE_COLOR_PROF_TRACKER +#define SEEN_EGE_COLOR_PROF_TRACKER +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is EGE Color Profile Tracker. + * + * The Initial Developer of the Original Code is + * Jon A. Cruz. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/** \file + * Object used to track ICC profiles attached to monitors and update as they change. + */ + +/* Note: this file should be kept compilable as both .cpp and .c */ + +#include +#include + + +G_BEGIN_DECLS + +#ifdef __cplusplus +typedef struct _GtkWidget GtkWidget; +#endif /* __cplusplus */ + +#define EGE_COLOR_PROF_TRACKER_TYPE ( ege_color_prof_tracker_get_type() ) +#define EGE_COLOR_PROF_TRACKER( obj ) ( G_TYPE_CHECK_INSTANCE_CAST( (obj), EGE_COLOR_PROF_TRACKER_TYPE, EgeColorProfTracker) ) +#define EGE_COLOR_PROF_TRACKER_CLASS( klass ) ( G_TYPE_CHECK_CLASS_CAST( (klass), EGE_COLOR_PROF_TRACKER_TYPE, EgeColorProfTrackerClass) ) +#define IS_EGE_COLOR_PROF_TRACKER( obj ) ( G_TYPE_CHECK_INSTANCE_TYPE( (obj), EGE_COLOR_PROF_TRACKER_TYPE) ) +#define IS_EGE_COLOR_PROF_TRACKER_CLASS( klass ) ( G_TYPE_CHECK_CLASS_TYPE( (klass), EGE_COLOR_PROF_TRACKER_TYPE) ) +#define EGE_COLOR_PROF_TRACKER_GET_CLASS( obj ) ( G_TYPE_INSTANCE_GET_CLASS( (obj), EGE_COLOR_PROF_TRACKER_TYPE, EgeColorProfTrackerClass) ) + +typedef struct _EgeColorProfTracker EgeColorProfTracker; +typedef struct _EgeColorProfTrackerClass EgeColorProfTrackerClass; +typedef struct _EgeColorProfTrackerPrivate EgeColorProfTrackerPrivate; + +/** + * Instance structure of EgeColorProfTracker. + */ +struct _EgeColorProfTracker +{ + /** Parent instance structure. */ + GObject object; + + /** Pointer to private instance data. */ + EgeColorProfTrackerPrivate *private_data; +}; + +/** + * Class structure of EgeColorProfTracker. + */ +struct _EgeColorProfTrackerClass +{ + /** Parent class structure. */ + GObjectClass parent_class; + + void (*changed) (EgeColorProfTracker* tracker); +}; + +/** Standard Gtk type function */ +GType ege_color_prof_tracker_get_type( void ); + +/** + * Creates a new EgeColorProfTracker instance. + */ +EgeColorProfTracker* ege_color_prof_tracker_new( GtkWidget* target ); + +void ege_color_prof_tracker_get_profile( EgeColorProfTracker const * tracker, gpointer* ptr, guint* len ); + +G_END_DECLS + +#endif /* SEEN_EGE_COLOR_PROF_TRACKER */ diff --git a/src/widgets/desktop-widget.cpp b/src/widgets/desktop-widget.cpp index 3562e7b2a..cdfac93f1 100644 --- a/src/widgets/desktop-widget.cpp +++ b/src/widgets/desktop-widget.cpp @@ -55,6 +55,7 @@ #include "dialogs/swatches.h" #include "conn-avoid-ref.h" #include "ege-select-one-action.h" +#include "ege-color-prof-tracker.h" #if defined (SOLARIS_2_8) #include "round.h" @@ -87,6 +88,8 @@ static void sp_desktop_widget_realize (GtkWidget *widget); static gint sp_desktop_widget_event (GtkWidget *widget, GdkEvent *event, SPDesktopWidget *dtw); +static void sp_dtw_color_profile_event(GtkWidget *widget, SPDesktopWidget *dtw); + static void sp_desktop_widget_adjustment_value_changed (GtkAdjustment *adj, SPDesktopWidget *dtw); static void sp_desktop_widget_namedview_modified (SPObject *obj, guint flags, SPDesktopWidget *dtw); @@ -272,7 +275,16 @@ sp_desktop_widget_init (SPDesktopWidget *dtw) dtw->vscrollbar = gtk_vscrollbar_new (GTK_ADJUSTMENT (dtw->vadj)); gtk_box_pack_start (GTK_BOX (dtw->vscrollbar_box), dtw->vscrollbar, TRUE, TRUE, 0); gtk_table_attach (GTK_TABLE (canvas_tbl), dtw->vscrollbar_box, 2, 3, 0, 2, (GtkAttachOptions)(GTK_SHRINK), (GtkAttachOptions)(GTK_FILL), 0, 0); - + + dtw->cms_adjust = sp_button_new_from_data( Inkscape::ICON_SIZE_DECORATION, + SP_BUTTON_TYPE_TOGGLE, + NULL, + "swatches", + _("Adjust the display"), + dtw->tt ); + gtk_widget_set_sensitive(dtw->cms_adjust, FALSE); + gtk_table_attach( GTK_TABLE(canvas_tbl), dtw->cms_adjust, 2, 3, 2, 3, (GtkAttachOptions)(GTK_SHRINK), (GtkAttachOptions)(GTK_SHRINK), 0, 0); + /* Canvas */ dtw->canvas = SP_CANVAS (sp_canvas_new_aa ()); GTK_WIDGET_SET_FLAGS (GTK_WIDGET (dtw->canvas), GTK_CAN_FOCUS); @@ -284,10 +296,10 @@ sp_desktop_widget_init (SPDesktopWidget *dtw) gtk_table_attach (GTK_TABLE (canvas_tbl), GTK_WIDGET(dtw->canvas), 1, 2, 1, 2, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), 0, 0); /* Dock */ - bool create_dock = - prefs_get_int_attribute_limited ("options.dialogtype", "value", Inkscape::UI::Dialog::FLOATING, 0, 1) == + bool create_dock = + prefs_get_int_attribute_limited ("options.dialogtype", "value", Inkscape::UI::Dialog::FLOATING, 0, 1) == Inkscape::UI::Dialog::DOCK; - + if (create_dock) { dtw->dock = new Inkscape::UI::Widget::Dock(); @@ -296,17 +308,17 @@ sp_desktop_widget_init (SPDesktopWidget *dtw) paned->pack1(*Glib::wrap(canvas_tbl)); paned->pack2(dtw->dock->getWidget(), Gtk::FILL); - /* Prevent the paned from catching F6 and F8 by unsetting the default callbacks */ + /* Prevent the paned from catching F6 and F8 by unsetting the default callbacks */ if (GtkPanedClass *paned_class = GTK_PANED_CLASS (G_OBJECT_GET_CLASS (paned->gobj()))) { paned_class->cycle_child_focus = NULL; paned_class->cycle_handle_focus = NULL; } - gtk_table_attach (GTK_TABLE (tbl), GTK_WIDGET (paned->gobj()), 1, 2, 1, 2, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), + gtk_table_attach (GTK_TABLE (tbl), GTK_WIDGET (paned->gobj()), 1, 2, 1, 2, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), 0, 0); } else { - gtk_table_attach (GTK_TABLE (tbl), GTK_WIDGET (canvas_tbl), 1, 2, 1, 2, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), + gtk_table_attach (GTK_TABLE (tbl), GTK_WIDGET (canvas_tbl), 1, 2, 1, 2, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), 0, 0); } @@ -371,6 +383,9 @@ sp_desktop_widget_init (SPDesktopWidget *dtw) //dtw->layer_selector->set_size_request(-1, SP_ICON_SIZE_BUTTON); gtk_box_pack_start(GTK_BOX(dtw->statusbar), GTK_WIDGET(dtw->layer_selector->gobj()), FALSE, FALSE, 1); + dtw->_tracker = ege_color_prof_tracker_new(GTK_WIDGET(dtw->layer_selector->gobj())); + g_signal_connect( G_OBJECT(dtw->_tracker), "changed", G_CALLBACK(sp_dtw_color_profile_event), dtw ); + dtw->select_status_eventbox = gtk_event_box_new (); dtw->select_status = gtk_label_new (NULL); #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 6 @@ -429,7 +444,7 @@ sp_desktop_widget_destroy (GtkObject *object) void SPDesktopWidget::updateTitle(gchar const* uri) { - Gtk::Window *window = (Gtk::Window*)gtk_object_get_data (GTK_OBJECT(this), "window"); + Gtk::Window *window = (Gtk::Window*)gtk_object_get_data (GTK_OBJECT(this), "window"); if (window) { gchar const *fname = ( TRUE @@ -572,6 +587,11 @@ sp_desktop_widget_event (GtkWidget *widget, GdkEvent *event, SPDesktopWidget *dt return FALSE; } +void sp_dtw_color_profile_event(GtkWidget */*widget*/, SPDesktopWidget */*dtw*/) +{ + // Handle profile changes +} + void sp_dtw_desktop_activate (SPDesktopWidget *dtw) { @@ -612,7 +632,7 @@ SPDesktopWidget::shutdown() _("Save changes to document \"%s\" before closing?\n\n" "If you close without saving, your changes will be discarded."), SP_DOCUMENT_NAME(doc)); - // fix for bug 1767940: + // fix for bug 1767940: GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(GTK_MESSAGE_DIALOG(dialog)->label), GTK_CAN_FOCUS); GtkWidget *close_button; @@ -631,16 +651,16 @@ SPDesktopWidget::shutdown() switch (response) { case GTK_RESPONSE_YES: { - Gtk::Window *window = (Gtk::Window*)gtk_object_get_data (GTK_OBJECT(this), "window"); - - sp_document_ref(doc); + Gtk::Window *window = (Gtk::Window*)gtk_object_get_data (GTK_OBJECT(this), "window"); + + sp_document_ref(doc); if (sp_file_save_document(*window, doc)) { sp_document_unref(doc); } else { // save dialog cancelled or save failed sp_document_unref(doc); return TRUE; } - + break; } case GTK_RESPONSE_NO: @@ -668,7 +688,7 @@ SPDesktopWidget::shutdown() "Do you want to save this file in another format?"), SP_DOCUMENT_NAME(doc), Inkscape::Extension::db.get(sp_document_repr_root(doc)->attribute("inkscape:output_extension"))->get_name()); - // fix for bug 1767940: + // fix for bug 1767940: GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(GTK_MESSAGE_DIALOG(dialog)->label), GTK_CAN_FOCUS); GtkWidget *close_button; @@ -687,17 +707,17 @@ SPDesktopWidget::shutdown() switch (response) { case GTK_RESPONSE_YES: { - sp_document_ref(doc); - - Gtk::Window *window = (Gtk::Window*)gtk_object_get_data (GTK_OBJECT(this), "window"); - + sp_document_ref(doc); + + Gtk::Window *window = (Gtk::Window*)gtk_object_get_data (GTK_OBJECT(this), "window"); + if (sp_file_save_dialog(*window, doc)) { sp_document_unref(doc); } else { // save dialog cancelled or save failed sp_document_unref(doc); return TRUE; } - + break; } case GTK_RESPONSE_NO: @@ -721,7 +741,7 @@ SPDesktopWidget::shutdown() prefs_set_int_attribute("desktop.geometry", "maximized", maxed); gint w, h, x, y; desktop->getWindowGeometry(x, y, w, h); - // Don't save geom for maximized windows. It + // Don't save geom for maximized windows. It // just tells you the current maximized size, which is not // as useful as whatever value it had previously. if (!maxed && !full) { @@ -800,7 +820,7 @@ SPDesktopWidget::getWindowGeometry (gint &x, gint &y, gint &w, gint &h) gboolean vis = GTK_WIDGET_VISIBLE (this); Gtk::Window *window = (Gtk::Window*)gtk_object_get_data (GTK_OBJECT(this), "window"); - + if (window) { window->get_size (w, h); @@ -811,8 +831,8 @@ SPDesktopWidget::getWindowGeometry (gint &x, gint &y, gint &w, gint &h) void SPDesktopWidget::setWindowPosition (NR::Point p) { - Gtk::Window *window = (Gtk::Window*)gtk_object_get_data (GTK_OBJECT(this), "window"); - + Gtk::Window *window = (Gtk::Window*)gtk_object_get_data (GTK_OBJECT(this), "window"); + if (window) { window->move (gint(round(p[NR::X])), gint(round(p[NR::Y]))); @@ -822,8 +842,8 @@ SPDesktopWidget::setWindowPosition (NR::Point p) void SPDesktopWidget::setWindowSize (gint w, gint h) { - Gtk::Window *window = (Gtk::Window*)gtk_object_get_data (GTK_OBJECT(this), "window"); - + Gtk::Window *window = (Gtk::Window*)gtk_object_get_data (GTK_OBJECT(this), "window"); + if (window) { window->set_default_size (w, h); @@ -908,10 +928,10 @@ sp_desktop_widget_maximize(SPDesktopWidget *dtw) if (dtw->desktop->is_maximized()) { gtk_window_unmaximize(topw); } else { - // Save geometry to prefs before maximizing so that + // Save geometry to prefs before maximizing so that // something useful is stored there, because GTK doesn't maintain // a separate non-maximized size. - if (!dtw->desktop->is_iconified() && !dtw->desktop->is_fullscreen()) + if (!dtw->desktop->is_iconified() && !dtw->desktop->is_fullscreen()) { gint w, h, x, y; dtw->getWindowGeometry(x, y, w, h); @@ -935,10 +955,10 @@ sp_desktop_widget_fullscreen(SPDesktopWidget *dtw) gtk_window_unfullscreen(topw); // widget layout is triggered by the resulting window_state_event } else { - // Save geometry to prefs before maximizing so that + // Save geometry to prefs before maximizing so that // something useful is stored there, because GTK doesn't maintain // a separate non-maximized size. - if (!dtw->desktop->is_iconified() && !dtw->desktop->is_maximized()) + if (!dtw->desktop->is_iconified() && !dtw->desktop->is_maximized()) { gint w, h, x, y; dtw->getWindowGeometry(x, y, w, h); diff --git a/src/widgets/desktop-widget.h b/src/widgets/desktop-widget.h index 18348e594..a0b97f9d8 100644 --- a/src/widgets/desktop-widget.h +++ b/src/widgets/desktop-widget.h @@ -22,6 +22,10 @@ #include +// forward declaration +typedef struct _EgeColorProfTracker EgeColorProfTracker; + + #define SP_TYPE_DESKTOP_WIDGET (sp_desktop_widget_get_type ()) #define SP_DESKTOP_WIDGET(o) (GTK_CHECK_CAST ((o), SP_TYPE_DESKTOP_WIDGET, SPDesktopWidget)) #define SP_DESKTOP_WIDGET_CLASS(k) (GTK_CHECK_CLASS_CAST ((k), SP_TYPE_DESKTOP_WIDGET, SPDesktopWidgetClass)) @@ -65,7 +69,7 @@ struct SPDesktopWidget { SPDesktop *desktop; Gtk::Window *window; - + // The root vbox of the window layout. GtkWidget *vbox; @@ -82,6 +86,7 @@ struct SPDesktopWidget { GtkWidget *hruler_box, *vruler_box; // eventboxes for setting tooltips GtkWidget *sticky_zoom; + GtkWidget *cms_adjust; GtkWidget *coord_status; GtkWidget *coord_status_x; GtkWidget *coord_status_y; @@ -95,7 +100,7 @@ struct SPDesktopWidget { Inkscape::UI::Widget::SelectedStyle *selected_style; gint coord_status_id, select_status_id; - + unsigned int _interaction_disabled_counter; SPCanvas *canvas; @@ -106,6 +111,8 @@ struct SPDesktopWidget { Inkscape::Widgets::LayerSelector *layer_selector; + EgeColorProfTracker* _tracker; + struct WidgetStub : public Inkscape::UI::View::EditWidgetInterface { SPDesktopWidget *_dtw; SPDesktop *_dt; @@ -115,9 +122,9 @@ struct SPDesktopWidget { { _dtw->updateTitle (uri); } virtual Gtk::Window* getWindow() { return _dtw->window; } - virtual void layout() + virtual void layout() { sp_desktop_widget_layout (_dtw); } - virtual void present() + virtual void present() { _dtw->presentWindow(); } virtual void getGeometry (gint &x, gint &y, gint &w, gint &h) { _dtw->getWindowGeometry (x, y, w, h); } @@ -139,11 +146,11 @@ struct SPDesktopWidget { { return _dtw->shutdown(); } virtual void destroy() { - if(_dtw->window != NULL) - delete _dtw->window; - _dtw->window = NULL; - } - + if(_dtw->window != NULL) + delete _dtw->window; + _dtw->window = NULL; + } + virtual void requestCanvasUpdate() { _dtw->requestCanvasUpdate(); } virtual void requestCanvasUpdateAndWait() @@ -189,7 +196,7 @@ struct SPDesktopWidget { }; WidgetStub *stub; - + void setMessage(Inkscape::MessageType type, gchar const *message); NR::Point window_get_pointer(); bool shutdown();