/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 .
*/
#include <sal/config.h>
#include <cstddef> #include <unistd.h>
#include <unx/cpdmgr.hxx>
#include <osl/file.h> #include <osl/thread.h>
#include <rtl/ustrbuf.hxx> #include <sal/log.hxx>
#include <config_dbus.h> #include <config_gio.h>
usingnamespace psp;
#if ENABLE_DBUS && ENABLE_GIO // Function to execute when name is acquired on the bus void CPDManager::onNameAcquired(GDBusConnection* connection, const gchar*, gpointer user_data)
{
gchar* contents; // Get Interface for introspection if (!g_file_get_contents(FRONTEND_INTERFACE, &contents, nullptr, nullptr)) return;
// TODO: I don't know how this should work when we have multiple // sources with multiple possible defaults for each // if( pDest->is_default ) // m_aDefaultPrinter = aPrinterName;
rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
aPrinter.m_aInfo.m_aComment = OStringToOUString(pDest->info, aEncoding);
aPrinter.m_aInfo.m_aLocation = OStringToOUString(pDest->location, aEncoding); // note: the parser that goes with the PrinterInfo // is created implicitly by the JobData::operator=() // when it detects the NULL ptr m_pParser. // if we wanted to fill in the parser here this // would mean we'd have to send a dbus message for each and // every printer - which would be really bad runtime // behaviour
aPrinter.m_aInfo.m_pParser = nullptr;
aPrinter.m_aInfo.m_aContext.setParser(nullptr);
std::unordered_map<OUString, PPDContext>::const_iterator c_it
= m_aDefaultContexts.find(aUniqueName); if (c_it != m_aDefaultContexts.end())
{
aPrinter.m_aInfo.m_pParser = c_it->second.getParser();
aPrinter.m_aInfo.m_aContext = c_it->second;
}
aPrinter.m_aInfo.m_aDriverName = "CPD:" + aUniqueName;
m_aPrinters[aUniqueName] = aPrinter;
} #endif
if (!pEnv || !*pEnv)
{ // interface description XML files are needed in 'onNameAcquired()' if (!g_file_test(FRONTEND_INTERFACE, G_FILE_TEST_IS_REGULAR)
|| !g_file_test(BACKEND_INTERFACE, G_FILE_TEST_IS_REGULAR))
{ return nullptr;
}
if (dest_it != m_aCPDDestMap.end())
{
CPDPrinter* pDest = dest_it->second;
GVariant* ret = nullptr;
GError* error = nullptr;
ret = g_dbus_proxy_call_sync(pDest->backend, "GetAllOptions",
g_variant_new("(s)", (pDest->id)), G_DBUS_CALL_FLAGS_NONE, -1,
nullptr, &error); if (ret != nullptr && error == nullptr)
{ // TODO: These keys need to be redefined to preserve usage across libreoffice // InputSlot - media-col.media-source? // Font - not needed now as it is required only for ps and we are using pdf // Dial? - for FAX (need to look up PWG spec)
int num_attribute;
GVariantIter *iter_attr, *iter_supported_values;
g_variant_get(ret, "(ia(ssia(s)))", &num_attribute, &iter_attr);
rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
PPDKey* pKey = nullptr;
OUString aValueName;
PPDValue* pValue;
std::vector<PPDKey*> keys;
std::unordered_map<OUString, OUString> aOptionDefaults; for (int i = 0; i < num_attribute; i++)
{ char *name, *default_value; int num_supported_values;
g_variant_iter_loop(iter_attr, "(ssia(s))", &name, &default_value,
&num_supported_values, &iter_supported_values);
OUString aOptionName = OStringToOUString(name, aEncoding);
OUString aDefaultValue = OStringToOUString(default_value, aEncoding); if (aOptionName == "sides")
{ // Duplex key is used throughout for checking Duplex Support
aOptionName = u"Duplex"_ustr;
} elseif (aOptionName == "printer-resolution")
{ // Resolution key is used in places
aOptionName = u"Resolution"_ustr;
} elseif (aOptionName == "media")
{ // PageSize key is used in many places
aOptionName = u"PageSize"_ustr;
}
aOptionDefaults[aOptionName] = aDefaultValue;
pKey = new PPDKey(aOptionName);
// If number of values are 0, this is not settable via UI if (num_supported_values > 0 && aDefaultValue != "NA")
pKey->m_bUIOption = true;
bool bDefaultFound = false;
for (int j = 0; j < num_supported_values; j++)
{ char* value;
g_variant_iter_loop(iter_supported_values, "(s)", &value);
aValueName = OStringToOUString(value, aEncoding); if (aOptionName == "Duplex")
{ // Duplex key matches against very specific Values if (aValueName == "one-sided")
{
aValueName = u"None"_ustr;
} elseif (aValueName == "two-sided-long-edge")
{
aValueName = u"DuplexNoTumble"_ustr;
} elseif (aValueName == "two-sided-short-edge")
{
aValueName = u"DuplexTumble"_ustr;
}
}
pValue = pKey->insertValue(aValueName, PPDValueType::Quoted); if (!pValue) continue;
pValue->m_aValue = aValueName;
if (aValueName.equals(aDefaultValue))
{
pKey->m_pDefaultValue = pValue;
bDefaultFound = true;
}
} // This could be done to ensure default values also appear as options: if (!bDefaultFound && pKey->m_bUIOption)
{ // pValue = pKey->insertValue( aDefaultValue, PPDValueType::Quoted ); // if( pValue ) // pValue->m_aValue = aDefaultValue;
}
keys.emplace_back(pKey);
}
void CPDManager::initialize()
{ // get normal printers, clear printer list
PrinterInfoManager::initialize(); #if ENABLE_DBUS && ENABLE_GIO
g_bus_own_name_on_connection(m_pConnection, "org.libreoffice.print-dialog",
G_BUS_NAME_OWNER_FLAGS_NONE, onNameAcquired, onNameLost, this,
nullptr);
g_dbus_connection_signal_subscribe(m_pConnection, // DBus Connection
nullptr, // Sender Name "org.openprinting.PrintBackend", // Sender Interface "PrinterAdded", // Signal Name
nullptr, // Object Path
nullptr, // arg0 behaviour
G_DBUS_SIGNAL_FLAGS_NONE, // Signal Flags
printerAdded, // Callback Function this, nullptr);
g_dbus_connection_signal_subscribe(m_pConnection, // DBus Connection
nullptr, // Sender Name "org.openprinting.PrintBackend", // Sender Interface "PrinterRemoved", // Signal Name
nullptr, // Object Path
nullptr, // arg0 behaviour
G_DBUS_SIGNAL_FLAGS_NONE, // Signal Flags
printerRemoved, // Callback Function this, nullptr);
// remove everything that is not a CUPS printer and not // a special purpose printer (PDF, Fax)
std::unordered_map<OUString, Printer>::iterator it = m_aPrinters.begin(); while (it != m_aPrinters.end())
{ if (m_aCPDDestMap.contains(it->first))
{
++it; continue;
}
if (!it->second.m_aInfo.m_aFeatures.isEmpty())
{
++it; continue;
}
it = m_aPrinters.erase(it);
} #endif
}
if (dest_it == m_aCPDDestMap.end()) return PrinterInfoManager::setupJobContextData(rData);
std::unordered_map<OUString, Printer>::iterator p_it = m_aPrinters.find(rData.m_aPrinterName); if (p_it == m_aPrinters.end()) // huh ?
{
SAL_WARN("vcl.unx.print", "CPD printer list in disorder, " "no dest for printer "
<< rData.m_aPrinterName); return;
}
if (p_it->second.m_aInfo.m_pParser == nullptr)
{ // in turn calls createCPDParser // which updates the printer info
p_it->second.m_aInfo.m_pParser = PPDParser::getParser(p_it->second.m_aInfo.m_aDriverName);
} if (p_it->second.m_aInfo.m_aContext.getParser() == nullptr)
{
OUString aPrinter; if (p_it->second.m_aInfo.m_aDriverName.startsWith("CPD:"))
aPrinter = p_it->second.m_aInfo.m_aDriverName.copy(4); else
aPrinter = p_it->second.m_aInfo.m_aDriverName;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.