File indexing completed on 2024-04-14 04:16:23
0001 /******************************************************************** 0002 KolorServer - color server based on the X Color Management Specification 0003 This file is part of the KDE project. 0004 0005 Copyright (C) 2012 Casian Andrei <skeletk13@gmail.com> 0006 0007 Redistribution and use in source and binary forms, with or without 0008 modification, are permitted provided that the following conditions 0009 are met: 0010 0011 1. Redistributions of source code must retain the above copyright 0012 notice, this list of conditions and the following disclaimer. 0013 2. Redistributions in binary form must reproduce the above copyright 0014 notice, this list of conditions and the following disclaimer in the 0015 documentation and/or other materials provided with the distribution. 0016 0017 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 0018 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 0019 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 0020 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 0021 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 0022 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 0023 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 0024 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 0025 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 0026 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 0027 *********************************************************************/ 0028 0029 #include <KDebug> 0030 0031 #include "color-lookup-table.h" 0032 #include "display.h" 0033 #include "output.h" 0034 #include "screen.h" 0035 0036 #include <oyranos_devices.h> 0037 #include <oyFilterNode_s.h> 0038 #include <oyRectangle_s.h> 0039 0040 namespace KolorServer 0041 { 0042 0043 /* 0044 * Color Output 0045 */ 0046 0047 ColorOutput::ColorOutput(Screen *parent, int index) 0048 : m_parent(parent) 0049 , m_index(index) 0050 { 0051 /* select profiles matching actual capabilities */ 0052 icc_profile_flags = oyICCProfileSelectionFlagsFromOptions( OY_CMM_STD, "//" OY_TYPE_STD "/icc_color", NULL, 0 ); 0053 } 0054 0055 ColorOutput::~ColorOutput() 0056 { 0057 if (profile()) { 0058 // Move profile atoms back 0059 moveProfileAtoms(false); 0060 } 0061 0062 // Clean profile atoms 0063 if (hasProfileAtom()) 0064 cleanProfileAtom(); 0065 } 0066 0067 oyProfile_s *ColorOutput::profile() 0068 { 0069 return m_cc.destinationProfile(); 0070 } 0071 0072 void ColorOutput::setProfile(oyProfile_s* profile) 0073 { 0074 m_cc.setDestinationProfile(profile); 0075 } 0076 0077 const QString& ColorOutput::name() 0078 { 0079 return m_name; 0080 } 0081 0082 const Clut& ColorOutput::colorLookupTable() const 0083 { 0084 return m_cc.colorLookupTable(); 0085 } 0086 0087 bool ColorOutput::hasProfileAtom() 0088 { 0089 X11::Display *display = m_parent->display(); 0090 X11::Window rootWindow = m_parent->rootWindow(); 0091 X11::Atom a = iccProfileAtom(display, m_index, true); 0092 long unsigned int n; 0093 0094 void *data = X11::fetchProperty(display, rootWindow, a, XA_CARDINAL, &n, False); 0095 if (data) 0096 X11::XFree(data); 0097 0098 return n != 0; 0099 } 0100 0101 void ColorOutput::cleanProfileAtom() 0102 { 0103 kDebug(); 0104 X11::Display *display = m_parent->display(); 0105 X11::Atom a = iccProfileAtom(display, m_index, true); 0106 X11::XFlush(display); 0107 X11::deleteProperty(display, a); 0108 } 0109 0110 void ColorOutput::updateConfiguration(oyConfig_s *device, bool init) 0111 { 0112 kDebug() << device << init; 0113 0114 if (init) { 0115 if (!m_cc.getDeviceProfile(device)) 0116 kError() << "Unable to get device profile"; 0117 } 0118 0119 if (profile()) { 0120 moveProfileAtoms(true); // TODO really true? 0121 } else { 0122 kDebug() << "No profile found for output" << m_index << m_name; 0123 } 0124 0125 setup(); 0126 } 0127 0128 X11::Atom ColorOutput::iccProfileAtom(X11::Display *display, int num, bool forServer) 0129 { 0130 QByteArray atomName; 0131 0132 if (forServer) 0133 atomName = XCM_DEVICE_PROFILE; 0134 else 0135 atomName = XCM_ICC_V0_3_TARGET_PROFILE_IN_X_BASE; 0136 0137 if (num) { 0138 atomName += "_"; 0139 atomName += QByteArray::number(num); 0140 } 0141 0142 return X11::XInternAtom(display, atomName.constData(), False); 0143 } 0144 0145 bool ColorOutput::getDeviceProfile(oyConfig_s *device) 0146 { 0147 kDebug() << device; 0148 0149 oyOption_s *o = 0; 0150 oyRectangle_s *r = 0; 0151 const char *device_name = 0; 0152 int error = 0; 0153 0154 o = oyConfig_Find(device, "device_rectangle"); 0155 if (!o) { 0156 kWarning() << "Request for monitor rectangle failed"; 0157 return false; 0158 } 0159 r = (oyRectangle_s*) oyOption_GetStruct(o, oyOBJECT_RECTANGLE_S); 0160 if (!r) { 0161 kWarning() << "Request for monitor rectangle failed"; 0162 return false; 0163 } 0164 oyOption_Release(&o); 0165 0166 m_rect = QRect(oyRectangle_GetGeo1( r, 0), 0167 oyRectangle_GetGeo1( r, 1), 0168 oyRectangle_GetGeo1( r, 2), 0169 oyRectangle_GetGeo1( r, 3)); 0170 0171 device_name = oyConfig_FindString(device, "device_name", 0); 0172 if (device_name && device_name[0]) { 0173 m_name = device_name; 0174 } else { 0175 kWarning() << "Unable to get device name"; 0176 m_name = QString::number(m_parent->screenNumber()); 0177 } 0178 0179 error = m_cc.getDeviceProfile(device); 0180 0181 return !error; 0182 } 0183 0184 void ColorOutput::setup() 0185 { 0186 kDebug(); 0187 m_cc.setup(m_name); 0188 } 0189 0190 /* 0191 The atom will hold a native ICC profile with the exposed device 0192 characteristics at the compositing window manager level. 0193 The colour server shall if no _ICC_DEVICE_PROFILE(_xxx) is set, copy the 0194 _ICC_PROFILE(_xxx) profiles to each equivalent _ICC_DEVICE_PROFILE(_xxx) atom. 0195 The _ICC_PROFILE(_xxx) profiles shall be replaced by a sRGB ICC profile. 0196 The counting in the atoms (_xxx) name section follows the rules outlined in 0197 the ICC Profile in X recommendation. After finishing the session the old 0198 state has to be recovered by copying any _ICC_DEVICE_PROFILE(_xxx) atoms 0199 content into the appropriate _ICC_PROFILE(_xxx) atoms and removing all 0200 _ICC_DEVICE_PROFILE(_xxx) atoms. 0201 The colour server must be aware about change property events indicating that 0202 a _ICC_PROFILE(_xxx) atom has changed by a external application and needs to 0203 move that profile to the appropriate _ICC_DEVICE_PROFILE(_xxx) atom and set 0204 the _ICC_PROFILE(_xxx) atom to sRGB as well. 0205 */ 0206 void ColorOutput::moveProfileAtoms(bool init) 0207 { 0208 kDebug() << "init: " << init; 0209 0210 X11::Display *display = m_parent->display(); 0211 X11::Window rootWindow = m_parent->rootWindow(); 0212 X11::Atom a1, a2, sourceAtom, targetAtom; 0213 0214 a1 = iccProfileAtom(display, m_index, false); 0215 a2 = iccProfileAtom(display, m_index, true); 0216 0217 // Select the atoms (source -> target) 0218 if (init) { 0219 sourceAtom = a1; 0220 targetAtom = a2; 0221 } else { 0222 sourceAtom = a2; 0223 targetAtom = a1; 0224 } 0225 0226 void *source; 0227 unsigned long sourceSize = 0, targetSize = 0; 0228 bool sourceExists = false, targetExists = false; 0229 bool updatedColorDesktopAtom = false; 0230 0231 X11::fetchProperty(display, rootWindow, targetAtom, XA_CARDINAL, &targetSize, False); 0232 targetExists = targetSize > 0; 0233 0234 if (!targetExists || 0235 ( targetExists && !init)) { 0236 // Copy the real device atom 0237 source = X11::fetchProperty(display, rootWindow, sourceAtom, XA_CARDINAL, &sourceSize, False); 0238 sourceExists = sourceSize > 0; 0239 0240 // _ICC_COLOR_DESKTOP atom is set before any _ICC_PROFILE(_xxx) changes. 0241 if (init) { 0242 Display::getInstance()->updateNetColorDesktopAtom(true); 0243 updatedColorDesktopAtom = true; 0244 } 0245 0246 if (sourceExists) 0247 X11::changeProperty(display, targetAtom, XA_CARDINAL, (const unsigned char *) source, sourceSize); 0248 if (source) 0249 X11::XFree(source); 0250 source = 0; 0251 sourceSize = 0; 0252 sourceExists = false; 0253 0254 if (init) { 0255 /* setup the OY_ICC_V0_3_TARGET_PROFILE_IN_X_BASE(_xxx) atom as document colour space */ 0256 size_t size = 0; 0257 oyProfile_s *screenDocumentProfile = oyProfile_FromStd(oyASSUMED_WEB, icc_profile_flags, 0); 0258 0259 if (screenDocumentProfile) { 0260 // Make sure the profile is ignored 0261 source = oyProfile_GetMem(screenDocumentProfile, &size, 0, malloc); 0262 oyProfile_Release(&screenDocumentProfile); 0263 sourceSize = size; 0264 sourceExists = sourceSize > 0; 0265 } else { 0266 kWarning() << "Could not get oyASSUMED_WEB profile"; 0267 source = 0; 0268 sourceSize = 0; 0269 sourceExists = false; 0270 } 0271 0272 if (!updatedColorDesktopAtom) { 0273 Display::getInstance()->updateNetColorDesktopAtom(true); // FIXME or false? 0274 updatedColorDesktopAtom = true; 0275 } 0276 0277 if (sourceExists) 0278 X11::changeProperty(display, sourceAtom, XA_CARDINAL, (const unsigned char *) source, sourceSize); 0279 if (source) 0280 free(source); 0281 source = 0; 0282 sourceSize = 0; 0283 sourceExists = false; 0284 } else { 0285 // Clear / erase the _ICC_DEVICE_PROFILE(_xxx) atom 0286 X11::deleteProperty(display, sourceAtom); 0287 } 0288 } else 0289 if (targetAtom && init) 0290 kWarning() << "ICC Color Server Atom already present:" << targetAtom << "size" << targetSize; 0291 } 0292 0293 } // KolorServer namespace