Back to index

scribus-ng  1.3.4.dfsg+svn20071115
objprinter.cpp
Go to the documentation of this file.
00001 /*
00002 For general Scribus (>=1.3.2) copyright and licensing information please refer
00003 to the COPYING file provided with the program. Following this notice may exist
00004 a copyright and/or license notice that predates the release of Scribus 1.3.2
00005 for which a new license (GPL+exception) is in place.
00006 */
00007 #include "objprinter.h"
00008 #include "cmdutil.h"
00009 #include "prefsmanager.h"
00010 
00011 #include <structmember.h>
00012 #include <qfileinfo.h>
00013 #include <qdir.h>
00014 #include <vector>
00015 #include "pslib.h"
00016 #include "gsutil.h"
00017 #include "scribuscore.h"
00018 #include "util.h"
00019 
00020 #ifdef HAVE_CUPS
00021 #include <cups/cups.h>
00022 #endif
00023 // these functions are located at utils.cpp
00024 bool SCRIBUS_API loadText(QString nam, QString *Buffer);
00025 void SCRIBUS_API ReOrderText(ScribusDoc *doc, ScribusView *view);
00026 // end of utils.cpp
00027 
00028 
00029 typedef struct
00030 {
00031        PyObject_HEAD
00032        PyObject *allPrinters; // list of strings - names of installed printers
00033        PyObject *printer;  // string - selected printer
00034        PyObject *file;  // string - name of file to print into (eg. output.ps)
00035        PyObject *cmd; // string - if "" use standard command else use this as command (eg. "kprinter", "xpp" ...)
00036        PyObject *pages; // list of integers - pages to be printed
00037        int copies; // numer of printed copies
00038        PyObject *separation; // string - No; All; Cyan; Magenta; Yellow; Black
00039        int color; // bool - do we print in color=1 or greyscale=0
00040        int useICC; // bool - do we use ICC Profiles 0 = No 1 = Yes
00041        int pslevel; // integer - 1, 2 or 3 level of used postscript
00042        int mph; // bool - mirror pages horizontally
00043        int mpv; // bool - mirror pages vertically
00044        int ucr; // bool - Under Color Removal
00045 } Printer;
00046 
00047 
00048 static void Printer_dealloc(Printer* self)
00049 {
00050        Py_XDECREF(self->allPrinters);
00051        Py_XDECREF(self->printer);
00052        Py_XDECREF(self->file);
00053        Py_XDECREF(self->cmd);
00054        Py_XDECREF(self->pages);
00055        Py_XDECREF(self->separation);
00056        self->ob_type->tp_free((PyObject *)self);
00057 }
00058 
00059 static PyObject * Printer_new(PyTypeObject *type, PyObject */*args*/, PyObject */*kwds*/)
00060 {
00061 // do not create new object if there is no opened document
00062        if (!ScCore->primaryMainWindow()->HaveDoc) {
00063               PyErr_SetString(PyExc_SystemError, "Need to open document first");
00064               return NULL;
00065        }
00066 
00067        Printer *self;
00068        self = (Printer *)type->tp_alloc(type, 0);
00069        if (self != NULL) {
00070 // set allPrinters attribute
00071               self->allPrinters = PyList_New(0);
00072               if (self->allPrinters == NULL){
00073                      Py_DECREF(self);
00074                      return NULL;
00075               }
00076 // set printer attribute
00077               self->printer = PyString_FromString("");
00078               if (self->printer == NULL){
00079                      Py_DECREF(self);
00080                      return NULL;
00081               }
00082 // set file attribute
00083               self->file = PyString_FromString("");
00084               if (self->file == NULL){
00085                      Py_DECREF(self);
00086                      return NULL;
00087               }
00088 // set cmd attribute
00089               self->cmd = PyString_FromString("");
00090               if (self->cmd == NULL){
00091                      Py_DECREF(self);
00092                      return NULL;
00093               }
00094 // set pages attribute
00095               self->pages = PyList_New(0);
00096               if (self->pages == NULL){
00097                      Py_DECREF(self);
00098                      return NULL;
00099               }
00100 // set separation attribute
00101               self->separation = PyString_FromString("No");
00102               if (self->separation == NULL){
00103                      Py_DECREF(self);
00104                      return NULL;
00105               }
00106 // set color attribute
00107               self->color = 1;
00108 // set useICC attribute
00109               self->useICC = 0;
00110 // set pslevel attribute
00111               self->pslevel = 3;
00112 // set mph attribute
00113               self->mph = 0;
00114 // set mpv attribute
00115               self->mpv = 0;
00116 // set ucr attribute
00117               self->ucr = 1;
00118 // set copies attribute
00119               self->copies = 1;
00120        }
00121        return (PyObject *) self;
00122 }
00123 
00124 static int Printer_init(Printer *self, PyObject */*args*/, PyObject */*kwds*/)
00125 {
00126 // pool system for installed printers
00127 // most code is stolen and little adopted from druck.cpp
00128        PyObject *allPrinters = PyList_New(0);
00129        if (allPrinters){
00130               Py_DECREF(self->allPrinters);
00131               self->allPrinters = allPrinters;
00132        }
00133 #ifdef HAVE_CUPS
00134        cups_dest_t *dests;
00135        int num_dests = cupsGetDests(&dests);
00136        for (int i = 0; i < num_dests; ++i) {
00137               if (dests[i].name != NULL) {
00138                      PyObject *tmp = PyString_FromString(dests[i].name);
00139                      if (tmp) {
00140                             PyList_Append(self->allPrinters, tmp);
00141                             Py_DECREF(tmp);
00142                      }
00143               }
00144        }
00145        cupsFreeDests(num_dests, dests);
00146 #else
00147        QString Pcap;
00148        // loadText is defined in utils.cpp
00149        if (loadText("/etc/printcap", &Pcap))
00150        {
00151               QTextStream ts(&Pcap, IO_ReadOnly);
00152               while(!ts.atEnd())
00153               {
00154                      QStringList wt;
00155                      QString tmp = ts.readLine();
00156                      if (tmp.isEmpty())
00157                             continue;
00158                      if ((tmp[0] != '#') && (tmp[0] != ' ') && (tmp[0] != '\n') && (tmp[0] != '\t'))
00159                      {
00160                             tmp = tmp.stripWhiteSpace();
00161                             tmp = tmp.left(tmp.length() - (tmp.right(2) == ":\\" ? 2 : 1));
00162                             wt = QStringList::split("|", tmp);
00163                             PyObject *tmppr = PyString_FromString(wt[0]);
00164                             if (tmppr){
00165                                    PyList_Append(self->allPrinters, tmppr);
00166                                    Py_DECREF(tmppr);
00167                             }
00168                      }
00169               }
00170        }
00171 #endif
00172        PyObject *tmp2 = PyString_FromString("File");
00173        PyList_Append(self->allPrinters, tmp2);
00174        Py_DECREF(tmp2);
00175 // as defaut set to print into file
00176        PyObject *printer = NULL;
00177        printer = PyString_FromString("File");
00178        if (printer){
00179               Py_DECREF(self->printer);
00180               self->printer = printer;
00181        }
00182 // set defaul name of file to print into
00183        QString tf = ScCore->primaryMainWindow()->doc->PDF_Options.Datei;
00184        if (tf.isEmpty()) {
00185               QFileInfo fi = QFileInfo(ScCore->primaryMainWindow()->doc->DocName);
00186               tf = fi.dirPath()+"/"+fi.baseName()+".pdf";
00187        }
00188        PyObject *file = NULL;
00189        file = PyString_FromString(tf.ascii());
00190        if (file){
00191               Py_DECREF(self->file);
00192               self->file = file;
00193        } else {
00194               PyErr_SetString(PyExc_SystemError, "Can not initialize 'file' attribute");
00195               return -1;
00196        }
00197 // alternative printer commands default to ""
00198        PyObject *cmd = NULL;
00199        cmd = PyString_FromString("");
00200        if (cmd){
00201               Py_DECREF(self->cmd);
00202               self->cmd = cmd;
00203        }
00204 // if document exist when created Printer instance
00205 // set to print all pages
00206        PyObject *pages = NULL;
00207        int num = 0;
00208        if (ScCore->primaryMainWindow()->HaveDoc)
00209               // which one should I use ???
00210               // new = ScCore->primaryMainWindow()->view->Pages.count()
00211               num = ScCore->primaryMainWindow()->doc->Pages->count();
00212        pages = PyList_New(num);
00213        if (pages){
00214               Py_DECREF(self->pages);
00215               self->pages = pages;
00216        }
00217        for (int i = 0; i<num; i++) {
00218               PyObject *tmp=NULL;
00219               tmp = PyInt_FromLong((long)i+1L); // instead of 1 put here first page number
00220               if (tmp)
00221                      PyList_SetItem(self->pages, i, tmp);
00222        }
00223 // do not print separation
00224        PyObject *separation = NULL;
00225        separation = PyString_FromString("No");
00226        if (separation){
00227               Py_DECREF(self->separation);
00228               self->separation = separation;
00229        }
00230 // print in color
00231        self->color = 1;
00232 // do not use ICC Profile
00233        self->useICC = 0;
00234 // use PostScrip level 3
00235        self->pslevel = 3;
00236 // do not mirror pages
00237        self->mph = 0;
00238 // do not mirror pages
00239        self->mpv = 0;
00240 // apply Under Color Removal as default
00241        self->ucr = 1;
00242 // number of copies
00243        self->copies = 1;
00244        return 0;
00245 }
00246 
00247 static PyMemberDef Printer_members[] = {
00248        {const_cast<char*>("copies"), T_INT, offsetof(Printer, copies), 0, const_cast<char*>("Number of copies")},
00249        {const_cast<char*>("color"), T_INT, offsetof(Printer, color), 0, const_cast<char*>("Print in color.\n\t True - color  --  Default\n\t False - greyscale")},
00250        {const_cast<char*>("useICC"), T_INT, offsetof(Printer, useICC), 0, const_cast<char*>("Use ICC Profile\n\tTrue\n\tFalse  --  Default")},
00251        {const_cast<char*>("pslevel"), T_INT, offsetof(Printer, pslevel), 0, const_cast<char*>("PostScript Level\nCan be 1 or 2 or 3    -- Default is 3.")},
00252        {const_cast<char*>("mph"), T_INT, offsetof(Printer, mph), 0, const_cast<char*>("Mirror Pages Horizontal\n\tTrue\n\tFalse  --  Default")},
00253        {const_cast<char*>("mpv"), T_INT, offsetof(Printer, mpv), 0, const_cast<char*>("Mirror Pages Vertical\n\t True\n\tFalse  --  Default")},
00254        {const_cast<char*>("ucr"), T_INT, offsetof(Printer, ucr), 0, const_cast<char*>("Apply Under Color Removal\n\tTrue  --  Default\n\tFalse")},
00255        {NULL, 0, 0, 0, NULL} // sentinel
00256 };
00257 
00258 /* Here begins Getter & Setter functions */
00259 
00260 static PyObject *Printer_getallPrinters(Printer *self, void */*closure*/)
00261 {
00262        Py_INCREF(self->allPrinters);
00263        return self->allPrinters;
00264 }
00265 
00266 static int Printer_setallPrinters(Printer */*self*/, PyObject */*value*/, void */*closure*/)
00267 {
00268        PyErr_SetString(PyExc_ValueError, "'allPrinters' attribute is READ-ONLY");
00269        return -1;
00270 }
00271 
00272 static PyObject *Printer_getprinter(Printer *self, void */*closure*/)
00273 {
00274        Py_INCREF(self->printer);
00275        return self->printer;
00276 }
00277 
00278 static int Printer_setprinter(Printer *self, PyObject *value, void */*closure*/)
00279 {
00280        if (value == NULL) {
00281               PyErr_SetString(PyExc_TypeError, "Cannot delete 'printer' attribute.");
00282               return -1;
00283        }
00284        if (!PyString_Check(value)) {
00285               PyErr_SetString(PyExc_TypeError, "The 'printer' attribute value must be string.");
00286               return -1;
00287        }
00288        int n = PyList_Size(self->allPrinters);
00289        bool same = 0;
00290        for (int i = 0; i<n; i++)
00291               if (PyObject_RichCompareBool(value, PyList_GetItem(self->allPrinters, i), Py_EQ) == 1)
00292                      same = true;
00293        if (!same) {
00294               PyErr_SetString(PyExc_ValueError, "'printer' value can be only one of string in 'allPrinters' attribute ");
00295               return -1;
00296        }
00297        Py_DECREF(self->printer);
00298        Py_INCREF(value);
00299        self->printer = value;
00300        return 0;
00301 }
00302 
00303 static PyObject *Printer_getfile(Printer *self, void */*closure*/)
00304 {
00305        Py_INCREF(self->file);
00306        return self->file;
00307 }
00308 
00309 static int Printer_setfile(Printer *self, PyObject *value, void */*closure*/)
00310 {
00311        if (value == NULL) {
00312               PyErr_SetString(PyExc_TypeError, "Cannot delete 'file' attribute.");
00313               return -1;
00314        }
00315        if (!PyString_Check(value)) {
00316               PyErr_SetString(PyExc_TypeError, "The 'file' attribute value must be string.");
00317               return -1;
00318        }
00319        Py_DECREF(self->file);
00320        Py_INCREF(value);
00321        self->file = value;
00322        return 0;
00323 }
00324 
00325 static PyObject *Printer_getcmd(Printer *self, void */*closure*/)
00326 {
00327        Py_INCREF(self->cmd);
00328        return self->cmd;
00329 }
00330 
00331 static int Printer_setcmd(Printer *self, PyObject *value, void */*closure*/)
00332 {
00333        if (value == NULL) {
00334               PyErr_SetString(PyExc_TypeError, "Cannot delete 'cmd' attribute.");
00335               return -1;
00336        }
00337        if (!PyString_Check(value)) {
00338               PyErr_SetString(PyExc_TypeError, "The 'cmd' attribute value must be string.");
00339               return -1;
00340        }
00341        Py_DECREF(self->cmd);
00342        Py_INCREF(value);
00343        self->cmd = value;
00344        return 0;
00345 }
00346 
00347 static PyObject *Printer_getpages(Printer *self, void */*closure*/)
00348 {
00349        Py_INCREF(self->pages);
00350        return self->pages;
00351 }
00352 
00353 static int Printer_setpages(Printer *self, PyObject *value, void */*closure*/)
00354 {
00355        if (value == NULL) {
00356               PyErr_SetString(PyExc_TypeError, "Cannot delete 'pages' attribute.");
00357               return -1;
00358        }
00359        if (!PyList_Check(value)) {
00360               PyErr_SetString(PyExc_TypeError, "'pages' attribute value must be list of integers.");
00361               return -1;
00362        }
00363        int len = PyList_Size(value);
00364        for (int i = 0; i<len; i++){
00365               PyObject *tmp = PyList_GetItem(value, i);
00366               if (!PyInt_Check(tmp)){
00367                      PyErr_SetString(PyExc_TypeError, "'pages' attribute must be list containing only integers.");
00368                      return -1;
00369               }
00370               if (PyInt_AsLong(tmp) > static_cast<int>(ScCore->primaryMainWindow()->doc->Pages->count()) || PyInt_AsLong(tmp) < 1) {
00371                      PyErr_SetString(PyExc_ValueError, "'pages' value out of range.");
00372                      return -1;
00373               }
00374        }
00375        Py_DECREF(self->pages);
00376        Py_INCREF(value);
00377        self->pages = value;
00378        return 0;
00379 }
00380 
00381 static PyObject *Printer_getseparation(Printer *self, void */*closure*/)
00382 {
00383        Py_INCREF(self->separation);
00384        return self->separation;
00385 }
00386 
00387 static int Printer_setseparation(Printer *self, PyObject *value, void */*closure*/)
00388 {
00389        if (value == NULL) {
00390               PyErr_SetString(PyExc_TypeError, "Cannot delete 'separation' attribute.");
00391               return -1;
00392        }
00393        if (!PyString_Check(value)) {
00394               PyErr_SetString(PyExc_TypeError, "The 'separation' attribute value must be string.");
00395               return -1;
00396        }
00397        Py_DECREF(self->separation);
00398        Py_INCREF(value);
00399        self->separation = value;
00400        return 0;
00401 }
00402 
00403 
00404 static PyGetSetDef Printer_getseters [] = {
00405        {const_cast<char*>("allPrinters"), (getter)Printer_getallPrinters, (setter)Printer_setallPrinters, const_cast<char*>("List of installed printers  --  read only"), NULL},
00406        {const_cast<char*>("printer"), (getter)Printer_getprinter, (setter)Printer_setprinter, const_cast<char*>("Name of printer to use.\nDefault is 'File' for printing into file"), NULL},
00407        {const_cast<char*>("file"), (getter)Printer_getfile, (setter)Printer_setfile, const_cast<char*>("Name of file to print into"), NULL},
00408        {const_cast<char*>("cmd"), (getter)Printer_getcmd, (setter)Printer_setcmd, const_cast<char*>("Alternative Printer Command"), NULL},
00409        {const_cast<char*>("pages"), (getter)Printer_getpages, (setter)Printer_setpages, const_cast<char*>("List of pages to be printed"), NULL},
00410        {const_cast<char*>("separation"), (getter)Printer_getseparation, (setter)Printer_setseparation, const_cast<char*>("Print separationl\n\t 'No'  -- Default\n\t 'All'\n\t 'Cyan'\n\t 'Magenta'\n\t 'Yellow'\n\t 'Black'\nBeware of misspelling because check is not performed"), NULL},
00411        {NULL, NULL, NULL, NULL, NULL}  // sentinel
00412 };
00413 
00414 // Here we actually print
00415 static PyObject *Printer_print(Printer *self)
00416 {
00417        if (!ScCore->primaryMainWindow()->HaveDoc) {
00418               PyErr_SetString(PyExc_SystemError, "Need to open documetnt first");
00419               return NULL;
00420        }
00421 // copied from void ScribusMainWindow::slotFilePrint() in file scribus.cpp
00422        QString fna, prn, cmd, scmd, cc, data, SepName;
00423        QString printcomm;
00424        int Nr, PSLevel;
00425        bool fil, PSfile;
00426        PSfile = false;
00427 
00428 //    ReOrderText(ScCore->primaryMainWindow()->doc, ScCore->primaryMainWindow()->view);
00429        prn = QString(PyString_AsString(self->printer));
00430        fna = QString(PyString_AsString(self->file));
00431        fil = (QString(PyString_AsString(self->printer)) == QString("File")) ? true : false;
00432        std::vector<int> pageNs;
00433        PrintOptions options;
00434        for (int i = 0; i < PyList_Size(self->pages); ++i) {
00435               options.pageNumbers.push_back((int)PyInt_AsLong(PyList_GetItem(self->pages, i)));
00436        }
00437        Nr = (self->copies < 1) ? 1 : self->copies;
00438        SepName = QString(PyString_AsString(self->separation));
00439        options.separationName = SepName;
00440        options.outputSeparations =(SepName == QString("No")) ?  false : true;
00441        options.useColor = self->color;
00442        options.mirrorH = self->mph;
00443        options.mirrorV = self->mpv;
00444        options.useICC = self->useICC;
00445        options.doGCR = self->ucr;
00446        options.cropMarks = false;
00447        options.bleedMarks = false;
00448        options.registrationMarks = false;
00449        options.colorMarks = false;
00450        options.markOffset = 0.0;
00451        options.bleeds.Top = 0.0;
00452        options.bleeds.Left = 0.0;
00453        options.bleeds.Right = 0.0;
00454        options.bleeds.Bottom = 0.0;
00455        int psl = self->pslevel;
00456        if (psl < 1)
00457               psl = 1;
00458        else if (psl > 3)
00459               psl = 3;
00460        PSLevel = psl;
00461        printcomm = QString(PyString_AsString(self->cmd));
00462        QMap<QString, QMap<uint, FPointArray> > ReallyUsed;
00463        ReallyUsed.clear();
00464        ScCore->primaryMainWindow()->doc->getUsedFonts(ReallyUsed);
00465        PrefsManager *prefsManager=PrefsManager::instance();
00466        PSLib *dd = new PSLib(options, true, prefsManager->appPrefs.AvailFonts, ReallyUsed, ScCore->primaryMainWindow()->doc->PageColors, false, true);
00467        if (dd != NULL)
00468        {
00469               if (!fil)
00470                      fna = QDir::convertSeparators(prefsManager->preferencesLocation()+"/tmp.ps");
00471               PSfile = dd->PS_set_file(fna);
00472               fna = QDir::convertSeparators(fna);
00473               if (PSfile)
00474               {
00475                      options.setDevParam = false;
00476                      options.doClip = false;
00477                      options.doOverprint = false;
00478                      dd->CreatePS(ScCore->primaryMainWindow()->doc, options);
00479                      if (PSLevel != 3)
00480                      {
00481                             QString tmp;
00482                             QStringList opts;
00483                             opts.append( QString("-dDEVICEWIDTHPOINTS=%1").arg(tmp.setNum(ScCore->primaryMainWindow()->doc->pageWidth)) );
00484                             opts.append( QString("-dDEVICEHEIGHTPOINTS=%1").arg(tmp.setNum(ScCore->primaryMainWindow()->doc->pageHeight)) );
00485                             convertPS2PS(fna, fna+".tmp", opts, PSLevel);
00486                             moveFile( fna + ".tmp", fna );
00487                      }
00488 
00489                      if (!fil)
00490                      {
00491                             if (!printcomm.isEmpty())
00492                                    cmd = printcomm + " "+fna;
00493                             else
00494                             {
00495                                    cmd = "lpr -P" + prn;
00496                                    if (Nr > 1)
00497                                           cmd += " -#" + cc.setNum(Nr);
00498 #ifdef HAVE_CUPS
00499 // This need yet to be implemented by object Printer
00500 //                                 cmd += printer->PrinterOpts;
00501 #endif
00502                                    cmd += " "+fna;
00503                             }
00504                             system(cmd);
00505                             unlink(fna);
00506                      }
00507               }
00508               else {
00509                      delete dd;
00510                      PyErr_SetString(PyExc_SystemError, "Printing failed");
00511                      return NULL;
00512               }
00513               delete dd;
00514        }
00515 //     Py_INCREF(Py_None);
00516 //     return Py_None;
00517        Py_RETURN_NONE;
00518 }
00519 
00520 static PyMethodDef Printer_methods[] = {
00521        {const_cast<char*>("print"), (PyCFunction)Printer_print, METH_NOARGS, const_cast<char*>("Prints selected pages.")},
00522        {NULL, (PyCFunction)(0), 0, NULL} // sentinel
00523 };
00524 
00525 PyTypeObject Printer_Type = {
00526        PyObject_HEAD_INIT(NULL)   // PyObject_VAR_HEAD
00527        0,                    //
00528        const_cast<char*>("Printer"), // char *tp_name; /* For printing, in format "<module>.<name>" */
00529        sizeof(Printer),   // int tp_basicsize, /* For allocation */
00530        0,                   // int tp_itemsize; /* For allocation */
00531 
00532        /* Methods to implement standard operations */
00533 
00534        (destructor) Printer_dealloc, //     destructor tp_dealloc;
00535        0, //     printfunc tp_print;
00536        0, //     getattrfunc tp_getattr;
00537        0, //     setattrfunc tp_setattr;
00538        0, //     cmpfunc tp_compare;
00539        0, //     reprfunc tp_repr;
00540 
00541        /* Method suites for standard classes */
00542 
00543        0, //     PyNumberMethods *tp_as_number;
00544        0, //     PySequenceMethods *tp_as_sequence;
00545        0, //     PyMappingMethods *tp_as_mapping;
00546 
00547        /* More standard operations (here for binary compatibility) */
00548 
00549        0, //     hashfunc tp_hash;
00550        0, //     ternaryfunc tp_call;
00551        0, //     reprfunc tp_str;
00552        0, //     getattrofunc tp_getattro;
00553        0, //     setattrofunc tp_setattro;
00554 
00555        /* Functions to access object as input/output buffer */
00556        0, //     PyBufferProcs *tp_as_buffer;
00557 
00558        /* Flags to define presence of optional/expanded features */
00559        Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,    // long tp_flags;
00560 
00561        printer__doc__,      // char *tp_doc; /* Documentation string */
00562 
00563        /* Assigned meaning in release 2.0 */
00564        /* call function for all accessible objects */
00565        0, //     traverseproc tp_traverse;
00566 
00567        /* delete references to contained objects */
00568        0, //     inquiry tp_clear;
00569 
00570        /* Assigned meaning in release 2.1 */
00571        /* rich comparisons */
00572        0, //     richcmpfunc tp_richcompare;
00573 
00574        /* weak reference enabler */
00575        0, //     long tp_weaklistoffset;
00576 
00577        /* Added in release 2.2 */
00578        /* Iterators */
00579        0, //     getiterfunc tp_iter;
00580        0, //     iternextfunc tp_iternext;
00581 
00582        /* Attribute descriptor and subclassing stuff */
00583        Printer_methods, //     struct PyMethodDef *tp_methods;
00584        Printer_members, //     struct PyMemberDef *tp_members;
00585        Printer_getseters, //     struct PyGetSetDef *tp_getset;
00586        0, //     struct _typeobject *tp_base;
00587        0, //     PyObject *tp_dict;
00588        0, //     descrgetfunc tp_descr_get;
00589        0, //     descrsetfunc tp_descr_set;
00590        0, //     long tp_dictoffset;
00591        (initproc)Printer_init, //     initproc tp_init;
00592        0, //     allocfunc tp_alloc;
00593        Printer_new, //     newfunc tp_new;
00594        0, //     freefunc tp_free; /* Low-level free-memory routine */
00595        0, //     inquiry tp_is_gc; /* For PyObject_IS_GC */
00596        0, //     PyObject *tp_bases;
00597        0, //     PyObject *tp_mro; /* method resolution order */
00598        0, //     PyObject *tp_cache;
00599        0, //     PyObject *tp_subclasses;
00600        0, //     PyObject *tp_weaklist;
00601        0, //     destructor tp_del;
00602 
00603 #ifdef COUNT_ALLOCS
00604        /* these must be last and never explicitly initialized */
00605        //    int tp_allocs;
00606        //    int tp_frees;
00607        //    int tp_maxalloc;
00608        //    struct _typeobject *tp_next;
00609 #endif
00610 };