OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [tags/] [start/] [insight/] [libgui/] [src/] [tclwinprint.c] - Blame information for rev 578

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/* tclwinprint.c -- Tcl routines for printing on Windows.
2
   Copyright (C) 1997 Cygnus Solutions.
3
   Written by Ian Lance Taylor <ian@cygnus.com>.
4
 
5
   This file contains routines to support printing on Windows from
6
   Tcl.  */
7
 
8
#ifdef _WIN32
9
 
10
#include <windows.h>
11
 
12
#include <tcl.h>
13
#include <tk.h>
14
 
15
#include "subcommand.h"
16
#include "guitcl.h"
17
 
18
#include <wingdi.h>
19
 
20
#undef PRINT_BUFSIZE
21
#define PRINT_BUFSIZE 10240
22
 
23
/* FIXME: We need to dig into the Tk window implementation internals
24
   to convert a Tk Window to an HWND.  */
25
 
26
#include <tkWinInt.h>
27
 
28
/* This implementation is minimal.  It's just enough to print a text
29
   file.  Additional features can be added as necessary.
30
 
31
   One interesting idea that would fit into the Windows printing
32
   scheme would be to have printing generate a limited canvas widget,
33
   and permit Tk scripts to use canvas commands to draw items on the
34
   page.
35
 
36
   This file defines a Tcl command with subcommands.
37
 
38
   ide_winprint page_setup OPTIONS
39
       Invoke the Windows Page Setup dialog.  This will record
40
       information internally that will be used for later printing.
41
 
42
       Supported options:
43
           -parent WINDOW
44
               Set the parent window of the dialog box.  The dialog
45
               box is modal with respect to this window.  The default
46
               is the main window.
47
 
48
   ide_winprint print_text QUERYPROC TEXTPROC OPTIONS
49
       Print text.  This will start formatting the print job.  The
50
       user will still be able to interact with Tk.  Typically, a
51
       dialog box would be put up with a cancel button to permit the
52
       user to cancel the print job by calling ide_winprint abort.
53
 
54
       The QUERYPROC argument is a Tcl procedure which tells the print
55
       job what to do next.  This is invoked alternately with the text
56
       procedure until the print job is finished.  QUERYPROC is called
57
       first.  This should return one of the following strings:
58
           continue
59
               Just invoke the text procedure and continue
60
               printing.
61
           done
62
               The print job is finished.
63
           newpage
64
               Skip to a new page and continue printing.
65
 
66
       The TEXTPROC argument is a Tcl procedure which returns a single
67
       line of text to print.  This procedure will be invoked
68
       alternately with the query procedure until the query procedure
69
       indicates that the print job is complete.  Page breaks are
70
       handled automatically.
71
 
72
       Supported options:
73
           -dialog BOOLEAN
74
               Whether to display the Windows Print dialog.  The
75
               default is true.  If false, this will use the default
76
               printer.
77
           -parent WINDOW
78
               Set the parent window of the dialog box.  The dialog
79
               box is modal with respect to this window.  The default
80
               is the main window.
81
           -name STRING
82
               Set the name of the document.  The default name is the
83
               empty string.
84
           -pageproc PAGEPROC
85
               PAGEPROC is executed at the start of each new page.  It
86
               will be called with one argument, which is the page
87
               number.  It will be called before either QUERYPROC or
88
               TEXTPROC is called on this page.  If QUERYPROC never
89
               returns newpage, then PAGEPROC will always be invoked
90
               after a call to TEXTPROC.  PAGEPROC should return one
91
               of the following strings:
92
                   continue
93
                       Keep going.
94
                   done
95
                       Stop printing.
96
           -postscript
97
               Use PostScript output.
98
           -initproc INITPROC
99
               INITPROC is called at the start of the print job.
100
 
101
   ide_winprint abort
102
       Abort a print job in process.  If there is no current print
103
       job, this does nothing.
104
 
105
   */
106
 
107
/* An instance of this structure is the client data for the
108
   ide_winprint command.  */
109
 
110
struct winprint_data
111
{
112
  /* Information from the Page Setup dialog.  */
113
  PAGESETUPDLG *page_setup;
114
  /* This is set non-zero if the print job is aborted.  */
115
  int aborted;
116
};
117
 
118
/* Delete the ide_winprint command.  */
119
 
120
static void
121
winprint_command_deleted (ClientData cd)
122
{
123
  struct winprint_data *wd = (struct winprint_data *) cd;
124
 
125
  if (wd->page_setup != NULL)
126
    {
127
      /* FIXME: I don't know if we are supposed to free the hDevMode
128
         and hDevNames fields.  */
129
      Tcl_Free ((char *) wd->page_setup);
130
    }
131
 
132
  Tcl_Free ((char *) wd);
133
}
134
 
135
/* Implement ide_winprint page_setup.  */
136
 
137
static int
138
winprint_page_setup_command (ClientData cd, Tcl_Interp *interp, int argc,
139
                             char **argv)
140
{
141
  struct winprint_data *wd = (struct winprint_data *) cd;
142
  Tk_Window parent;
143
  int i, mode, ret;
144
  PAGESETUPDLG psd;
145
 
146
  parent = Tk_MainWindow (interp);
147
 
148
  for (i = 2; i < argc; i += 2)
149
    {
150
      if (i + 1 >= argc)
151
        {
152
          Tcl_ResetResult (interp);
153
          Tcl_AppendStringsToObj (Tcl_GetObjResult (interp),
154
                                  "value for \"", argv[i], "\" missing",
155
                                  (char *) NULL);
156
          return TCL_ERROR;
157
        }
158
 
159
      if (strcmp (argv[i], "-parent") == 0)
160
        {
161
          parent = Tk_NameToWindow (interp, argv[i + 1],
162
                                    Tk_MainWindow (interp));
163
          if (parent == NULL)
164
            return TCL_ERROR;
165
        }
166
      else
167
        {
168
          Tcl_ResetResult (interp);
169
          Tcl_AppendStringsToObj (Tcl_GetObjResult (interp),
170
                                  "unknown option \"", argv[i], "\"",
171
                                  (char *) NULL);
172
          return TCL_ERROR;
173
        }
174
    }
175
 
176
  if (wd->page_setup != NULL)
177
    psd = *wd->page_setup;
178
  else
179
    {
180
      memset (&psd, 0, sizeof (PAGESETUPDLG));
181
      psd.lStructSize = sizeof (PAGESETUPDLG);
182
      psd.Flags = PSD_DEFAULTMINMARGINS;
183
    }
184
 
185
  if (Tk_WindowId (parent) == None)
186
    Tk_MakeWindowExist (parent);
187
  psd.hwndOwner = Tk_GetHWND (Tk_WindowId (parent));
188
 
189
  mode = Tcl_SetServiceMode (TCL_SERVICE_ALL);
190
 
191
  ret = PageSetupDlg (&psd);
192
 
193
  (void) Tcl_SetServiceMode (mode);
194
 
195
  if (! ret)
196
    {
197
      DWORD code;
198
 
199
      code = CommDlgExtendedError ();
200
      if (code == 0)
201
        {
202
          /* The user pressed cancel.  */
203
          return TCL_OK;
204
        }
205
      else
206
        {
207
          char buf[20];
208
 
209
          sprintf (buf, "0x%lx", (unsigned long) code);
210
          Tcl_ResetResult (interp);
211
          Tcl_AppendStringsToObj (Tcl_GetObjResult (interp),
212
                                  "Windows common dialog error ", buf,
213
                                  (char *) NULL);
214
          return TCL_ERROR;
215
        }
216
    }
217
 
218
  if (wd->page_setup == NULL)
219
    wd->page_setup = (PAGESETUPDLG *) Tcl_Alloc (sizeof (PAGESETUPDLG));
220
 
221
  *wd->page_setup = psd;
222
 
223
  return TCL_OK;
224
}
225
 
226
/* The abort function needs a static variable (ewww).  */
227
 
228
static struct winprint_data *abort_wd;
229
 
230
/* This is the abort function we pass to the Windows print routine.  */
231
 
232
static BOOL CALLBACK
233
abort_function (HDC hdc, int code)
234
{
235
  while (Tcl_DoOneEvent (TCL_DONT_WAIT))
236
    ;
237
  return ! abort_wd->aborted;
238
}
239
 
240
/* Handle an error in a Windows system call.  */
241
 
242
static void
243
windows_error (Tcl_Interp *interp, const char *fn)
244
{
245
  char buf[20];
246
 
247
  sprintf (buf, "%lu", (unsigned long) GetLastError ());
248
  Tcl_ResetResult (interp);
249
  Tcl_AppendStringsToObj (Tcl_GetObjResult (interp),
250
                          "Windows error in ", fn, ": ", buf, (char *) NULL);
251
}
252
 
253
/* This structure holds the options for the ide_winprint print_text
254
   command.  */
255
 
256
struct print_text_options
257
{
258
  /* Whether to use the print dialog.  */
259
  int dialog;
260
  /* The parent window.  */
261
  char *parent;
262
  /* The document name.  */
263
  char *name;
264
  /* The page procedure.  */
265
  char *pageproc;
266
  /* The init procedure. This is called once before printing. */
267
  char *initproc;
268
  /* Print using PostScript? */
269
  int postscript;
270
};
271
 
272
/* Handle options for the ide_winprint print_text command.  */
273
 
274
static int
275
winprint_print_text_options (struct winprint_data *wd, Tcl_Interp *interp,
276
                             int argc, char **argv,
277
                             struct print_text_options *pto)
278
{
279
  int i;
280
 
281
  pto->dialog = 1;
282
  pto->parent = NULL;
283
  pto->name = "";
284
  pto->pageproc = NULL;
285
  pto->postscript = 0;
286
  pto->initproc = NULL;
287
 
288
  for (i = 4; i < argc; i += 2)
289
    {
290
      if (i + 1 >= argc)
291
        {
292
          Tcl_ResetResult (interp);
293
          Tcl_AppendStringsToObj (Tcl_GetObjResult (interp),
294
                                  "value for \"", argv[i], "\" missing",
295
                                  (char *) NULL);
296
          return TCL_ERROR;
297
        }
298
 
299
      if (strcmp (argv[i], "-dialog") == 0)
300
        {
301
          if (Tcl_GetBoolean (interp, argv[i + 1], &pto->dialog) != TCL_OK)
302
            return TCL_ERROR;
303
        }
304
      else if (strcmp (argv[i], "-parent") == 0)
305
        pto->parent = argv[i + 1];
306
      else if (strcmp (argv[i], "-name") == 0)
307
        pto->name = argv[i + 1];
308
      else if (strcmp (argv[i], "-pageproc") == 0)
309
        pto->pageproc = argv[i + 1];
310
      else if (strcmp (argv[i], "-initproc") == 0)
311
        pto->initproc = argv[i + 1];
312
      else if (strcmp (argv[i], "-postscript") == 0)
313
        pto->postscript = 1;
314
      else
315
        {
316
          Tcl_ResetResult (interp);
317
          Tcl_AppendStringsToObj (Tcl_GetObjResult (interp),
318
                                  "unknown option \"", argv[i], "\"",
319
                                  (char *) NULL);
320
          return TCL_ERROR;
321
        }
322
    }
323
 
324
  return TCL_OK;
325
}
326
 
327
/* Invoke the print dialog for the ide_winprint print_text command.
328
   We always call PrintDlg, even if the -dialog false option was used,
329
   because it returns the device context we use for printing.  */
330
 
331
static int
332
winprint_print_text_dialog (struct winprint_data *wd, Tcl_Interp *interp,
333
                            const struct print_text_options *pto,
334
                            PRINTDLG *pd, int *cancelled)
335
{
336
  int mode, ret;
337
 
338
  *cancelled = 0;
339
 
340
  memset (pd, 0, sizeof (PRINTDLG));
341
  pd->lStructSize = sizeof (PRINTDLG);
342
 
343
  if (! pto->dialog)
344
    pd->Flags = PD_RETURNDEFAULT | PD_RETURNDC;
345
  else
346
    {
347
      Tk_Window parent;
348
 
349
      if (pto->parent == NULL)
350
        parent = Tk_MainWindow (interp);
351
      else
352
        {
353
          parent = Tk_NameToWindow (interp, pto->parent,
354
                                    Tk_MainWindow (interp));
355
          if (parent == NULL)
356
            return TCL_ERROR;
357
        }
358
      if (Tk_WindowId (parent) == None)
359
        Tk_MakeWindowExist (parent);
360
      pd->hwndOwner = Tk_GetHWND (Tk_WindowId (parent));
361
 
362
      if (wd->page_setup != NULL)
363
        {
364
          pd->hDevMode = wd->page_setup->hDevMode;
365
          pd->hDevNames = wd->page_setup->hDevNames;
366
        }
367
 
368
      pd->Flags = PD_NOSELECTION | PD_RETURNDC | PD_USEDEVMODECOPIES;
369
 
370
      pd->nCopies = 1;
371
      pd->nFromPage = 1;
372
      pd->nToPage = 1;
373
      pd->nMinPage = 1;
374
      pd->nMaxPage = 0xffff;
375
    }
376
 
377
  mode = Tcl_SetServiceMode (TCL_SERVICE_ALL);
378
 
379
  ret = PrintDlg (pd);
380
 
381
  (void) Tcl_SetServiceMode (mode);
382
 
383
  if (! ret)
384
    {
385
      DWORD code;
386
 
387
      code = CommDlgExtendedError ();
388
 
389
      /* For some errors, the print dialog will already have reported
390
         an error.  We treat those as though the user pressed cancel.
391
         Unfortunately, I do not know just which errors those are.  */
392
 
393
      if (code == 0 || code == PDERR_NODEFAULTPRN)
394
        {
395
          *cancelled = 1;
396
          return TCL_OK;
397
        }
398
      else
399
        {
400
          char buf[20];
401
 
402
          sprintf (buf, "0x%lx", (unsigned long) code);
403
          Tcl_ResetResult (interp);
404
          Tcl_AppendStringsToObj (Tcl_GetObjResult (interp),
405
                                  "Windows common dialog error ", buf,
406
                                  (char *) NULL);
407
          return TCL_ERROR;
408
        }
409
    }
410
 
411
  return TCL_OK;
412
}
413
 
414
/* Get the margins in device units.  */
415
 
416
static void
417
winprint_get_margins (struct winprint_data *wd, const PRINTDLG *pd,
418
                      int *top_ptr, int *left_ptr, int *bottom_ptr)
419
{
420
  int topmargin, leftmargin, bottommargin;
421
  int logx, logy;
422
 
423
  if (wd->page_setup == NULL)
424
    {
425
      /* Use 1 inch margins.  */
426
      topmargin = 1000;
427
      leftmargin = 1000;
428
      bottommargin = 1000;
429
    }
430
  else
431
    {
432
      topmargin = wd->page_setup->rtMargin.top;
433
      leftmargin = wd->page_setup->rtMargin.left;
434
      bottommargin = wd->page_setup->rtMargin.bottom;
435
      if ((wd->page_setup->Flags & PSD_INHUNDREDTHSOFMILLIMETERS) != 0)
436
        {
437
          topmargin = (topmargin * 1000) / 2540;
438
          leftmargin = (leftmargin * 1000) / 2540;
439
          bottommargin = (bottommargin * 1000) / 2540;
440
        }
441
    }
442
 
443
  logx = GetDeviceCaps (pd->hDC, LOGPIXELSX);
444
  logy = GetDeviceCaps (pd->hDC, LOGPIXELSY);
445
 
446
  topmargin = (topmargin * logy) / 1000;
447
  leftmargin = (leftmargin * logx) / 1000;
448
  bottommargin = (bottommargin * logy) / 1000;
449
 
450
  *top_ptr = topmargin;
451
  *left_ptr = leftmargin;
452
  *bottom_ptr = GetDeviceCaps (pd->hDC, VERTRES) - bottommargin;
453
}
454
 
455
/* Prepare to start printing.  */
456
 
457
static int
458
winprint_start (struct winprint_data *wd, Tcl_Interp *interp, PRINTDLG *pd,
459
                const struct print_text_options *pto, int *cancelled)
460
{
461
  DOCINFO di;
462
 
463
  *cancelled = 0;
464
 
465
  wd->aborted = 0;
466
 
467
  /* We have no way to pass information to the abort function, so we
468
     need to use a global variable.  */
469
  abort_wd = wd;
470
  if (! SetAbortProc (pd->hDC, abort_function))
471
    {
472
      windows_error (interp, "SetAbortFunc");
473
      return TCL_ERROR;
474
    }
475
 
476
  di.cbSize = sizeof (DOCINFO);
477
  di.lpszDocName = pto->name;
478
  di.lpszOutput = NULL;
479
  di.lpszDatatype = NULL;
480
  di.fwType = 0;
481
 
482
  if (StartDoc (pd->hDC, &di) <= 0)
483
    {
484
      if (GetLastError () == ERROR_CANCELLED)
485
        *cancelled = 1;
486
      else
487
        {
488
          windows_error (interp, "StartDoc");
489
          return TCL_ERROR;
490
        }
491
    }
492
 
493
  return TCL_OK;
494
}
495
 
496
/* Finish printing.  */
497
 
498
static int
499
winprint_finish (struct winprint_data *wd, Tcl_Interp *interp,
500
                 PRINTDLG *pd, int error)
501
{
502
  int ret;
503
 
504
  ret = TCL_OK;
505
 
506
  if (error || wd->aborted)
507
    AbortDoc (pd->hDC);
508
  else
509
    {
510
      if (EndDoc (pd->hDC) <= 0)
511
        {
512
          windows_error (interp, "EndDoc");
513
          ret = TCL_ERROR;
514
        }
515
    }
516
 
517
  DeleteDC (pd->hDC);
518
 
519
  return ret;
520
}
521
 
522
/* Values the ide_winprint print_text query or page procedure can
523
   return.  */
524
 
525
enum winprint_query { Q_CONTINUE, Q_NEWPAGE, Q_DONE };
526
 
527
/* Invoke the query or page procedure for ide_winprint print_text.  */
528
 
529
static int
530
winprint_print_text_invoke (Tcl_Interp *interp, char *proc, const char *name,
531
                            enum winprint_query *result)
532
{
533
  char *q;
534
 
535
  if (Tcl_Eval (interp, proc) == TCL_ERROR)
536
    return TCL_ERROR;
537
 
538
  q = Tcl_GetStringFromObj (Tcl_GetObjResult (interp), (int *) NULL);
539
  if (strcmp (q, "continue") == 0)
540
    *result = Q_CONTINUE;
541
  else if (strcmp (q, "newpage") == 0)
542
    *result = Q_NEWPAGE;
543
  else if (strcmp (q, "done") == 0)
544
    *result = Q_DONE;
545
  else
546
    {
547
      Tcl_ResetResult (interp);
548
      Tcl_AppendStringsToObj (Tcl_GetObjResult (interp),
549
                              "bad return from ", name, " procedure: \"",
550
                              q, "\"", (char *) NULL);
551
      return TCL_ERROR;
552
    }
553
 
554
  return TCL_OK;
555
}
556
 
557
/* Implement ide_winprint print_text.  */
558
static int
559
winprint_print_command (ClientData cd, Tcl_Interp *interp, int argc,
560
                             char **argv)
561
{
562
  struct winprint_data *wd = (struct winprint_data *) cd;
563
  char *queryproc;
564
  char *textproc;
565
  struct print_text_options pto;
566
  PRINTDLG pd;
567
  int cancelled;
568
  int top, bottom, left;
569
  TEXTMETRIC tm;
570
  POINT pt;
571
  int lineheight;
572
  int pageno;
573
  int error=0, done, needquery;
574
  struct {
575
         short len; /* Defined to be 16 bits.... */
576
         char buffer[PRINT_BUFSIZE+1];
577
  } indata;
578
 
579
  queryproc = argv[2];
580
  textproc = argv[3];
581
 
582
  if (winprint_print_text_options (wd, interp, argc, argv, &pto) != TCL_OK)
583
    return TCL_ERROR;
584
 
585
  if (winprint_print_text_dialog (wd, interp, &pto, &pd, &cancelled) != TCL_OK)
586
    return TCL_ERROR;
587
  if (cancelled)
588
    return TCL_OK;
589
 
590
  if (pto.postscript)
591
  {
592
        int eps_printing = 33;
593
        int result;
594
        short bresult = 1; /* EPS printing download suppressed */
595
        result = Escape (pd.hDC, eps_printing, sizeof (BOOL), (LPCSTR)&bresult, NULL);
596
        if ( result < 0 )
597
        {
598
                /* The EPSPRINTING escape failed! */
599
                Tcl_AppendElement(interp,
600
                   "ide_winprint: EPSPRINTING escape implemented but failed");
601
                DeleteDC (pd.hDC);
602
                return TCL_ERROR;
603
          }
604
  }
605
  else
606
  {
607
        winprint_get_margins(wd, &pd, &top, &left, &bottom);
608
  }
609
 
610
  if (winprint_start (wd, interp, &pd, &pto, &cancelled) != TCL_OK)
611
    {
612
      DeleteDC (pd.hDC);
613
      return TCL_ERROR;
614
    }
615
  if (cancelled)
616
    {
617
      DeleteDC (pd.hDC);
618
      return TCL_OK;
619
    }
620
 
621
  /* init and start init-procedure if available */
622
  if (pto.initproc != NULL)
623
  {
624
        Tcl_DString initStr;
625
        char buf[64];
626
        Tcl_DStringInit (&initStr);
627
        Tcl_DStringAppend (&initStr, pto.initproc, -1);
628
 
629
        /* Here we must pass the customer selection from the PrintDialog
630
         * as parameters for the init command, */
631
        /* From page */
632
        Tcl_DStringAppendElement (&initStr, "-frompage");
633
        sprintf (buf, "%i", pd.nFromPage);
634
        Tcl_DStringAppendElement (&initStr, buf);
635
        /* To Page */
636
        Tcl_DStringAppendElement (&initStr, "-topage");
637
        sprintf (buf, "%i", pd.nToPage);
638
        Tcl_DStringAppendElement (&initStr, buf);
639
        /* # Copies */
640
        Tcl_DStringAppendElement (&initStr, "-copies");
641
        sprintf (buf, "%i", pd.nCopies);
642
        Tcl_DStringAppendElement (&initStr, buf);
643
        /* Print Selection? */
644
        Tcl_DStringAppendElement (&initStr, "-selection");
645
        Tcl_DStringAppendElement (&initStr, (pd.Flags&PD_SELECTION) ? "1" : "0");
646
 
647
        /* Execute tcl/command */
648
        if (Tcl_Eval (interp, Tcl_DStringValue(&initStr)) != TCL_OK)
649
        {
650
              Tcl_DStringFree (&initStr);
651
              return TCL_ERROR;
652
        }
653
        Tcl_DStringFree (&initStr);
654
  }
655
 
656
  if (pto.postscript)
657
  {
658
    Tcl_DString pageStr;
659
    int status, retval, len, i;
660
    char *l, msgbuf[128];
661
    enum winprint_query q = 0;
662
 
663
    /* Note: NT 4.0 seems to leave the default CTM quite tiny! */
664
    strcpy (indata.buffer, "\r\nsave\r\ninitmatrix\r\n");
665
    indata.len = strlen(indata.buffer);
666
    Escape(pd.hDC, PASSTHROUGH, 0, (LPCSTR)&indata, NULL);
667
 
668
    /* Init command for page-procedure */
669
    if (pto.pageproc != NULL)
670
      {
671
        Tcl_DStringInit (&pageStr);
672
        Tcl_DStringAppend (&pageStr, pto.pageproc, -1);
673
        Tcl_DStringAppendElement (&pageStr, "-1");
674
      }
675
 
676
    /* Start printing */
677
    while (1)
678
      {
679
        /* Run page-procedure to update the display */
680
        status = winprint_print_text_invoke (interp, Tcl_DStringValue(&pageStr), "page", &q);
681
        if (status != TCL_OK || q == Q_DONE)
682
          {
683
            error = 1;
684
            break;
685
          }
686
 
687
        /* query next characters to send to printer */
688
        if (winprint_print_text_invoke (interp, queryproc, "query", &q) != TCL_OK)
689
          {
690
            error = 1;
691
            break;
692
          }
693
        if (q != Q_CONTINUE)
694
          {
695
            done = 1;
696
            break;
697
          }
698
        if (Tcl_Eval (interp, textproc) == TCL_ERROR)
699
          {
700
            error = 1;
701
            break;
702
          }
703
        l = Tcl_GetStringFromObj (Tcl_GetObjResult (interp), &len);
704
        for (i=0; i<len; i+=PRINT_BUFSIZE)
705
          {
706
            int lpos = min (PRINT_BUFSIZE, len-i);
707
            strncpy (indata.buffer, l+i, lpos);
708
            indata.buffer[lpos] = 0;
709
            indata.len = lpos;
710
 
711
            retval = Escape (pd.hDC, PASSTHROUGH, 0, (LPCSTR)&indata, NULL);
712
            if (retval < 0)
713
              {
714
                Tcl_AppendElement(interp, "ide_winprint: PASSTHROUGH Escape failed");
715
                error = 1;
716
                break;
717
              }
718
            else if (retval != indata.len)
719
              {
720
                sprintf(msgbuf, "ide_winprint: Short write (%d vs. %d)", retval, indata.len);
721
                Tcl_AppendElement(interp, msgbuf);
722
                error = 1;
723
                break;
724
              }
725
          }
726
      }
727
 
728
    strcpy (indata.buffer, "\r\nrestore\r\n");
729
    indata.len = strlen(indata.buffer);
730
    Escape(pd.hDC, PASSTHROUGH, 0, (LPCSTR)&indata, NULL);
731
  }
732
  else
733
    {
734
      GetTextMetrics (pd.hDC, &tm);
735
      pt.x = 0;
736
      pt.y = tm.tmHeight + tm.tmExternalLeading;
737
      LPtoDP (pd.hDC, &pt, 1);
738
      lineheight = pt.y;
739
 
740
      pageno = 1;
741
 
742
      /* The main print loop.  */
743
      done = 0;
744
      error = 0;
745
      needquery = 1;
746
      while (1)
747
        {
748
          int y;
749
 
750
          if (wd->aborted)
751
            break;
752
 
753
          /* Start a new page.  */
754
          if (pto.pageproc != NULL)
755
            {
756
              Tcl_DString ds;
757
              char buf[20];
758
              enum winprint_query q;
759
              int status;
760
 
761
              Tcl_DStringInit (&ds);
762
              Tcl_DStringAppend (&ds, pto.pageproc, -1);
763
              sprintf (buf, "%d", pageno);
764
              Tcl_DStringAppendElement (&ds, buf);
765
 
766
              status = winprint_print_text_invoke (interp, Tcl_DStringValue (&ds),
767
                                                   "page", &q);
768
 
769
              Tcl_DStringFree (&ds);
770
 
771
              if (status != TCL_OK)
772
                {
773
                  error = 1;
774
                  break;
775
                }
776
 
777
              if (q == Q_DONE)
778
                {
779
                  done = 1;
780
                  break;
781
                }
782
            }
783
 
784
          if (needquery)
785
            {
786
              enum winprint_query q;
787
 
788
              if (winprint_print_text_invoke (interp, queryproc, "query", &q)
789
                  != TCL_OK)
790
                {
791
                  error = 1;
792
                  break;
793
                }
794
 
795
              if (q == Q_DONE)
796
                {
797
                  done = 1;
798
                  break;
799
                }
800
 
801
              /* Ignore Q_NEWPAGE, since we're about to start a new page
802
                 anyhow.  */
803
 
804
              needquery = 0;
805
            }
806
 
807
          if (StartPage (pd.hDC) <= 0)
808
            {
809
              windows_error (interp, "StartPage");
810
              error = 1;
811
              break;
812
            }
813
 
814
          y = top;
815
 
816
          /* Print a page.  */
817
 
818
          while (1)
819
            {
820
              char *l;
821
              int len;
822
              enum winprint_query q;
823
 
824
              if (Tcl_Eval (interp, textproc) == TCL_ERROR)
825
                {
826
                  error = 1;
827
                  break;
828
                }
829
 
830
              l = Tcl_GetStringFromObj (Tcl_GetObjResult (interp), &len);
831
 
832
              TextOut (pd.hDC, left, y, l, len);
833
              y += lineheight;
834
 
835
              if (y >= bottom)
836
                {
837
                  needquery = 1;
838
                  break;
839
                }
840
 
841
              if (winprint_print_text_invoke (interp, queryproc, "query", &q)
842
                  != TCL_OK)
843
                {
844
                  error = 1;
845
                  break;
846
                }
847
 
848
              if (q == Q_DONE)
849
                {
850
                  done = 1;
851
                  break;
852
                }
853
              else if (q == Q_NEWPAGE)
854
                break;
855
            }
856
 
857
          if (error)
858
            break;
859
 
860
          if (EndPage (pd.hDC) <= 0)
861
            {
862
              /* It's OK for EndPage to return an error if the print job
863
                 was cancelled.  */
864
              if (! wd->aborted)
865
                {
866
                  windows_error (interp, "EndPage");
867
                  error = 1;
868
                }
869
              break;
870
            }
871
 
872
          if (done)
873
            break;
874
 
875
          ++pageno;
876
        }
877
    }
878
 
879
  if (winprint_finish (wd, interp, &pd, error) != TCL_OK)
880
    error = 1;
881
 
882
  if (error)
883
    return TCL_ERROR;
884
 
885
  Tcl_ResetResult (interp);
886
  return TCL_OK;
887
}
888
 
889
/* Implement ide_winprint abort.  */
890
 
891
static int
892
winprint_abort_command (ClientData cd, Tcl_Interp *interp, int argc,
893
                        char **argv)
894
{
895
  struct winprint_data *wd = (struct winprint_data *) cd;
896
 
897
  wd->aborted = 1;
898
  return TCL_OK;
899
}
900
 
901
/* The subcommand table.  */
902
 
903
static const struct ide_subcommand_table winprint_commands[] =
904
{
905
  { "page_setup",       winprint_page_setup_command,    2, -1 },
906
  { "print_text",       winprint_print_command, 4, -1 },
907
  { "print",         winprint_print_command,    6, -1 },
908
  { "abort",                winprint_abort_command,             2, 2 },
909
  { NULL, NULL, 0, 0 }
910
};
911
 
912
/* This function creates the ide_winprint Tcl command.  */
913
 
914
int
915
ide_create_winprint_command (Tcl_Interp *interp)
916
{
917
  struct winprint_data *wd;
918
 
919
  wd = (struct winprint_data *) Tcl_Alloc (sizeof *wd);
920
  wd->page_setup = NULL;
921
  wd->aborted = 0;
922
 
923
  return ide_create_command_with_subcommands (interp, "ide_winprint",
924
                                              winprint_commands,
925
                                              (ClientData) wd,
926
                                              winprint_command_deleted);
927
}
928
 
929
#endif /* _WIN32 */
930
 
931
 
932
 
933
 
934
 
935
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.