xref: /haiku/src/apps/terminal/TermWindow.cpp (revision 1ce9b0cb59525cee96af4e8838b152ec7261bf33)
1 /*
2  * Copyright (c) 2003-2004 Kian Duffy <myob@users.sourceforge.net>
3  * Copyright (C) 1998,99 Kazuho Okui and Takashi Murai.
4  * Copyright (c) 2004 Daniel Furrer <assimil8or@users.sourceforge.net>
5  *
6  * Distributed unter the terms of the MIT license.
7  */
8 #include <app/Application.h>
9 #include <Menu.h>
10 #include <MenuBar.h>
11 #include <MenuItem.h>
12 #include <ScrollBar.h>
13 #include <TextControl.h>
14 #include <PrintJob.h>
15 #include <Alert.h>
16 #include <float.h>
17 #include <WindowScreen.h>
18 #include <PropertyInfo.h>
19 
20 #include <stdio.h>
21 #include <sys/time.h>
22 #include <string>
23 #include <unistd.h>
24 
25 
26 #include "TermApp.h"
27 #include "TermParse.h"
28 #include "TermWindow.h"
29 #include "TermView.h"
30 #include "TermBuffer.h"
31 #include "TermBaseView.h"
32 #include "CodeConv.h"
33 #include "TermConst.h"
34 #include "PrefDlg.h"
35 #include "PrefView.h"
36 #include "PrefHandler.h"
37 #include "MenuUtil.h"
38 #include "spawn.h"
39 #include "ColorWindow.h"
40 
41 
42 // Global Preference Handler
43 extern PrefHandler *gTermPref;
44 //
45 // help and GPL URL
46 //
47 //#define URL_PREFIX  "file:///boot/home/config/settings/MuTerminal/help/"
48 //#define INDEX_FILE  "/index.html"
49 //#define GPL_FILE  "/gpl.html"
50 //#define CHLP_FILE   "file:///boot/beos/documentation/Shell%20Tools/index.html"
51 
52 extern int gNowCoding;  /* defined TermParce.cpp */
53 char gWindowName[256] = "Terminal";
54 
55 void SetCoding (int);
56 
57 /*
58  *
59  * CONSTRUCTOR and DESTRUCTOR
60  *
61  */
62 
63 ////////////////////////////////////////////////////////////////////////////
64 // TermWindow Constructer
65 //
66 ////////////////////////////////////////////////////////////////////////////
67 TermWindow::TermWindow( BRect frame, int32 windownumber)
68   : BWindow (frame, NULL, B_DOCUMENT_WINDOW, B_CURRENT_WORKSPACE)
69 {
70   sprintf(gWindowName,"Terminal %ld",windownumber);
71 
72   InitWindow();
73   SetWindowTitle();
74   fPrintSettings = NULL;
75   fPrefWindow = NULL;
76   fFindPanel = NULL;
77 
78 }
79 ////////////////////////////////////////////////////////////////////////////
80 // Desctuctor
81 //
82 ////////////////////////////////////////////////////////////////////////////
83 TermWindow::~TermWindow()
84 {
85   if (fWindowUpdate != NULL)
86     delete (fWindowUpdate);
87 }
88 
89 
90 //	#pragma mark - public methods
91 
92 
93 /** Initialize Window object. */
94 
95 void
96 TermWindow::InitWindow(void)
97 {
98 	// make menu bar
99 	SetupMenu();
100 
101 	// Setup font.
102 
103 	const char *family = gTermPref->getString(PREF_HALF_FONT_FAMILY);
104 
105 	BFont halfFont;
106 	halfFont.SetFamilyAndStyle(family, NULL);
107 	halfFont.SetSize(gTermPref->getFloat(PREF_HALF_FONT_SIZE));
108 	halfFont.SetSpacing(B_FIXED_SPACING);
109 
110 	family = gTermPref->getString(PREF_FULL_FONT_FAMILY);
111 
112 	BFont fullFont;
113 	fullFont.SetFamilyAndStyle(family, NULL);
114 	fullFont.SetSize(gTermPref->getFloat(PREF_FULL_FONT_SIZE));
115 	fullFont.SetSpacing(B_FIXED_SPACING);
116 
117 	// Make Terminal text view.
118 
119 	BRect textframe = Bounds();
120 	textframe.top = fMenubar->Bounds().bottom + 1.0;
121 
122 	fCodeConv = new CodeConv();
123 	fTermView = new TermView(Bounds(), fCodeConv);
124 
125 	/*
126 	 * MuTerm has two views. BaseView is window base view.
127 	 * TermView is character Terminal view on BaseView. It has paste
128 	 * on BaseView shift as VIEW_OFFSET.
129 	 */
130 	fBaseView = new TermBaseView(textframe, fTermView);
131 
132 	// Initialize TermView. (font, size and color)
133 
134 	fTermView->SetTermFont(&halfFont, &fullFont);
135 	BRect rect = fTermView->SetTermSize(gTermPref->getInt32(PREF_ROWS),
136 		gTermPref->getInt32(PREF_COLS), 1);
137 
138 	int width, height;
139 
140 	fTermView->GetFontSize(&width, &height);
141 	SetSizeLimits(MIN_COLS * width, MAX_COLS * width,
142 		MIN_COLS * height, MAX_COLS * height);
143 
144 	fTermView->SetTermColor();
145 	fBaseView->SetViewColor(gTermPref->getRGB(PREF_TEXT_BACK_COLOR));
146 
147 	// Add offset to baseview.
148 	rect.InsetBy(-VIEW_OFFSET, -VIEW_OFFSET);
149 
150 	// Resize Window
151 
152 	ResizeTo(rect.Width()+ B_V_SCROLL_BAR_WIDTH,
153 		rect.Height() + fMenubar->Bounds().Height());
154 
155 	fBaseView->ResizeTo(rect.Width(), rect.Height());
156 	fBaseView->AddChild(fTermView);
157 	fTermView->MoveBy(VIEW_OFFSET, VIEW_OFFSET);
158 
159 	// Make Scroll Bar.
160 
161 	BRect scrollRect(0, 0, B_V_SCROLL_BAR_WIDTH,
162 		rect.Height() - B_H_SCROLL_BAR_HEIGHT + 1);
163 
164 	scrollRect.OffsetBy(rect.Width() + 1, fMenubar->Bounds().Height());
165 
166 	BScrollBar *scrollBar = new BScrollBar(scrollRect, "scrollbar",
167 		fTermView, 0, 0, B_VERTICAL);
168 	fTermView->SetScrollBar(scrollBar);
169 
170 	AddChild(scrollBar);
171 	AddChild(fBaseView);
172 
173 	// Set fEditmenu's target to fTermView. (Oh!...)
174 	fEditmenu->SetTargetForItems(fTermView);
175 
176 	// Initialize TermParse
177 
178 	gNowCoding = longname2op(gTermPref->getString(PREF_TEXT_ENCODING));
179 	fTermParse = new TermParse();
180 	fTermParse->InitPtyReader(this);
181 	fTermParse->InitTermParse(fTermView, fCodeConv);
182 
183 	// Set Coding.
184 
185 	// Initialize MessageRunner.
186 	fWindowUpdate = new BMessageRunner(BMessenger(this),
187 		new BMessage (MSGRUN_WINDOW), 500000);
188 }
189 
190 
191 void
192 TermWindow::MenusBeginning(void)
193 {
194 	// Syncronize Encode Menu Pop-up menu and Preference.
195 	(fEncodingmenu->FindItem(op2longname(gNowCoding)))->SetMarked(true);
196 	BWindow::MenusBeginning();
197 }
198 
199 
200 void
201 TermWindow::SetupMenu(void)
202 {
203   PrefHandler menuText;
204 
205   LoadLocaleFile (&menuText);
206 
207   // Menu bar object.
208   fMenubar = new BMenuBar(Bounds(), "mbar");
209 
210   /*
211    * Make Fiile Menu.
212    */
213   fFilemenu = new BMenu("Terminal");
214   fFilemenu->AddItem(new BMenuItem("Switch Terminals", new BMessage(MENU_SWITCH_TERM),'G'));
215   fFilemenu->AddItem(new BMenuItem("Start New Terminal", new BMessage(MENU_NEW_TREM), 'N'));
216   fFilemenu->AddSeparatorItem();
217   fFilemenu->AddItem(new BMenuItem("Page Setup...", new BMessage(MENU_PAGE_SETUP)));
218   fFilemenu->AddItem(new BMenuItem("Print", new BMessage(MENU_PRINT),'P'));
219   fFilemenu->AddSeparatorItem();
220   fFilemenu->AddItem(new BMenuItem("About Terminal...", new BMessage(B_ABOUT_REQUESTED)));
221   fFilemenu->AddSeparatorItem();
222   fFilemenu->AddItem(new BMenuItem("Quit", new BMessage(MENU_FILE_QUIT), 'Q'));
223   fMenubar->AddItem(fFilemenu);
224 
225   /*
226    * Make Edit Menu.
227    */
228   fEditmenu = new BMenu ("Edit");
229   fEditmenu->AddItem (new BMenuItem ("Copy", new BMessage (B_COPY),'C'));
230   fEditmenu->AddItem (new BMenuItem ("Paste", new BMessage (B_PASTE),'V'));
231   fEditmenu->AddSeparatorItem ();
232   fEditmenu->AddItem (new BMenuItem ("Select All", new BMessage (B_SELECT_ALL), 'A'));
233   fEditmenu->AddItem (new BMenuItem ("Clear All", new BMessage (MENU_CLEAR_ALL), 'L'));
234 
235 /*
236   // TODO: Implement Finding
237   fEditmenu->AddSeparatorItem ();
238   fEditmenu->AddItem (new BMenuItem ("Find", new BMessage (MENU_FIND_STRING),'F'));
239   fEditmenu->AddItem (new BMenuItem ("Find Again", new BMessage (MENU_FIND_AGAIN), ']'));
240 */
241   fMenubar->AddItem (fEditmenu);
242 
243 
244   /*
245    * Make Help Menu.
246    */
247   fHelpmenu = new BMenu("Settings");
248   fWindowSizeMenu = new BMenu("Window Size");
249   	fWindowSizeMenu->AddItem(new BMenuItem("80x24", new BMessage(EIGHTYTWENTYFOUR)));
250   	fWindowSizeMenu->AddItem(new BMenuItem("80x25", new BMessage(EIGHTYTWENTYFIVE)));
251    	fWindowSizeMenu->AddItem(new BMenuItem("80x40", new BMessage(EIGHTYFORTY)));
252  	fWindowSizeMenu->AddItem(new BMenuItem("132x24", new BMessage(ONETHREETWOTWENTYFOUR)));
253  	fWindowSizeMenu->AddItem(new BMenuItem("132x25", new BMessage(ONETHREETWOTWENTYFIVE)));
254 
255  	// Considering we have this in the preferences window, this menu is not
256  	// needed and should not be shown if we are to not confuse the user
257 /*  fNewFontMenu = new BMenu("Font");
258 	fNewFontMenu->SetRadioMode(true);
259 		int32 numFamilies1 = count_font_families();
260 		for ( int32 i = 0; i < numFamilies1; i++ ) {
261 			font_family family;
262 			uint32 flags;
263 			if ( get_font_family(i, &family, &flags) == B_OK ) {
264 				fNewFontMenu->AddItem(item = new BMenuItem(family, new BMessage(MSG_FONT_CHANGED)));
265 			//	if (0 ==i) item->SetMarked(true);
266 			}
267 		}
268   fNewFontMenu->FindItem (gTermPref->getString(PREF_HALF_FONT_FAMILY))->SetMarked(true);
269 */
270 
271   fEncodingmenu = new BMenu("Font Encoding");
272   fEncodingmenu->SetRadioMode(true);
273   MakeEncodingMenu(fEncodingmenu, gNowCoding, true);
274   fHelpmenu->AddItem(fWindowSizeMenu);
275   fHelpmenu->AddItem(fEncodingmenu);
276 //  fHelpmenu->AddItem(fNewFontMenu);
277   fHelpmenu->AddSeparatorItem();
278   fHelpmenu->AddItem(new BMenuItem("Preferences", new BMessage(MENU_PREF_OPEN)));
279   fMenubar->AddItem(fHelpmenu);
280 
281   AddChild(fMenubar);
282 }
283 
284 
285 void
286 TermWindow::MessageReceived(BMessage *message)
287 {
288   int32 coding_id;
289   BRect r;
290   BFont halfFont;
291   BFont fullFont;
292 
293   switch (message->what) {
294 
295   case MENU_SWITCH_TERM:
296     be_app->PostMessage(MENU_SWITCH_TERM);
297     break;
298 
299   case MENU_NEW_TREM:
300     be_app->PostMessage(MENU_NEW_TREM);
301     break;
302 
303   case MENU_PREF_OPEN:
304     if (!fPrefWindow){
305       fPrefWindow = new PrefDlg(this);
306     }else{
307       fPrefWindow->Activate();
308     }
309     break;
310 
311   case MSG_PREF_CLOSED:
312     fPrefWindow = NULL;
313     break;
314 
315   case MENU_FILE_QUIT:
316     be_app->PostMessage(B_QUIT_REQUESTED);
317     break;
318   case MENU_ENCODING:
319     message->FindInt32 ("op", &coding_id);
320     gNowCoding = coding_id;
321     SetCoding (coding_id);
322     this->SetWindowTitle ();
323     break;
324 
325     /*
326      * Extended B_SET_PROPERTY. Dispatch this message,
327      * Set coding ID.
328      */
329   case B_SET_PROPERTY:
330   {
331     int32 i;
332     BMessage spe;
333     message->GetCurrentSpecifier(&i, &spe);
334     if (!strcmp("encode", spe.FindString("property", i))){
335       message->FindInt32 ("data",  &coding_id);
336       gNowCoding = coding_id;
337       SetCoding (coding_id);
338 
339       message->SendReply(B_REPLY);
340     }else{
341       BWindow::MessageReceived(message);
342     }
343     break;
344   }
345 
346     /*
347      * Extended B_GET_PROPERTY. Dispatch this message,
348      * reply now coding ID.
349      */
350   case B_GET_PROPERTY:
351   {
352     int32 i;
353     BMessage spe;
354     message->GetCurrentSpecifier(&i, &spe);
355     if (!strcmp("encode", spe.FindString("property", i))){
356       BMessage reply(B_REPLY);
357       reply.AddInt32("result", gNowCoding);
358       message->SendReply(&reply);
359     }else if (!strcmp("tty", spe.FindString("property", i))){
360       BMessage reply(B_REPLY);
361       reply.AddString("result", &tty_name[8]);
362       message->SendReply(&reply);
363     }else{
364       BWindow::MessageReceived(message);
365     }
366     break;
367   }
368 
369   /*
370    * Message from Preference panel.
371    */
372   case MSG_ROWS_CHANGED:
373   case MSG_COLS_CHANGED:
374     r = fTermView->SetTermSize (gTermPref->getInt32 (PREF_ROWS),
375               gTermPref->getInt32 (PREF_COLS),
376               0);
377 
378     ResizeTo (r.Width()+ B_V_SCROLL_BAR_WIDTH + VIEW_OFFSET * 2,
379         r.Height()+fMenubar->Bounds().Height() + VIEW_OFFSET *2);
380     break;
381 
382   case MSG_HALF_FONT_CHANGED:
383   case MSG_FULL_FONT_CHANGED:
384   case MSG_HALF_SIZE_CHANGED:
385   case MSG_FULL_SIZE_CHANGED:
386 
387     halfFont.SetFamilyAndStyle (gTermPref->getString(PREF_HALF_FONT_FAMILY),
388         NULL);
389     halfFont.SetSize (gTermPref->getFloat(PREF_HALF_FONT_SIZE));
390     halfFont.SetSpacing (B_FIXED_SPACING);
391 
392     fullFont.SetFamilyAndStyle (gTermPref->getString(PREF_FULL_FONT_FAMILY),
393         NULL);
394     fullFont.SetSize (gTermPref->getFloat(PREF_FULL_FONT_SIZE));
395     fullFont.SetSpacing (B_FIXED_SPACING);
396 
397     fTermView->SetTermFont (&halfFont, &fullFont);
398     r = fTermView->SetTermSize (0, 0, 0);
399 
400     int width, height;
401 
402     fTermView->GetFontSize (&width, &height);
403 
404     SetSizeLimits (MIN_COLS * width, MAX_COLS * width,
405 		   MIN_COLS * height, MAX_COLS * height);
406 
407 
408 
409     ResizeTo (r.Width()+ B_V_SCROLL_BAR_WIDTH + VIEW_OFFSET * 2,
410         r.Height()+fMenubar->Bounds().Height() + VIEW_OFFSET * 2);
411 
412     fTermView->Invalidate();
413     break;
414 
415 	case EIGHTYTWENTYFOUR:
416 		gTermPref->setString(PREF_COLS, "80");
417 		gTermPref->setString(PREF_ROWS, "24");
418 	   	this->PostMessage (MSG_ROWS_CHANGED);
419 		this->PostMessage (MSG_COLS_CHANGED);
420 	break;
421 
422 	case EIGHTYTWENTYFIVE:
423 		gTermPref->setString(PREF_COLS, "80");
424 		gTermPref->setString(PREF_ROWS, "25");
425 	   	this->PostMessage (MSG_ROWS_CHANGED);
426 	   	this->PostMessage (MSG_COLS_CHANGED);
427 	break;
428 
429 	case EIGHTYFORTY:
430 		gTermPref->setString(PREF_COLS, "80");
431 		gTermPref->setString(PREF_ROWS, "40");
432 	   	this->PostMessage (MSG_ROWS_CHANGED);
433 	   	this->PostMessage (MSG_COLS_CHANGED);
434 	break;
435 
436 	case ONETHREETWOTWENTYFOUR:
437 		gTermPref->setString(PREF_COLS, "132");
438 		gTermPref->setString(PREF_ROWS, "24");
439 	   	this->PostMessage (MSG_ROWS_CHANGED);
440 	   	this->PostMessage (MSG_COLS_CHANGED);
441 	break;
442 
443 	case ONETHREETWOTWENTYFIVE:
444 		gTermPref->setString(PREF_COLS, "132");
445 		gTermPref->setString(PREF_ROWS, "25");
446 	   	this->PostMessage (MSG_ROWS_CHANGED);
447 	   	this->PostMessage (MSG_COLS_CHANGED);
448 	break;
449 
450 	case MSG_FONT_CHANGED:
451     	gTermPref->setString (PREF_HALF_FONT_FAMILY, fNewFontMenu->FindMarked()->Label());
452     	this->PostMessage (MSG_HALF_FONT_CHANGED);
453     break;
454 
455 
456   case MSG_COLOR_CHANGED:
457     fBaseView->SetViewColor (gTermPref->getRGB (PREF_TEXT_BACK_COLOR));
458     fTermView->SetTermColor ();
459     fBaseView->Invalidate();
460     fTermView->Invalidate();
461     break;
462 
463   case MENU_PAGE_SETUP:
464     DoPageSetup ();
465     break;
466   case MENU_PRINT:
467     DoPrint ();
468     break;
469 
470   case MSGRUN_WINDOW:
471     fTermView->UpdateSIGWINCH ();
472     break;
473 
474 	case B_ABOUT_REQUESTED:
475 		be_app->PostMessage(B_ABOUT_REQUESTED);
476 		break;
477 
478   default:
479     BWindow::MessageReceived(message);
480     break;
481   }
482 }
483 ////////////////////////////////////////////////////////////////////////////
484 // WindowActivated (bool)
485 //  Dispatch Mesasge.
486 ////////////////////////////////////////////////////////////////////////////
487 void
488 TermWindow::WindowActivated (bool )
489 {
490 
491 }
492 
493 ////////////////////////////////////////////////////////////////////////////
494 // Quit (void)
495 //  Quit Application.
496 ////////////////////////////////////////////////////////////////////////////
497 //void
498 //TermWindow::colRequested() {
499 //	colWindow *colW=new colWindow("Colours for Terminal");
500 //	colW->Show();
501 //	}
502 
503 
504 void
505 TermWindow::Quit(void)
506 {
507   delete fTermParse;
508   delete fCodeConv;
509   if(fPrefWindow) fPrefWindow->PostMessage (B_QUIT_REQUESTED);
510     be_app->PostMessage (B_QUIT_REQUESTED, be_app);
511   BWindow::Quit ();
512 }
513 
514 
515 bool
516 TermWindow::QuitRequested(void)
517 {
518 
519   return true;
520 }
521 ////////////////////////////////////////////////////////////////////////////
522 // int GetTimeZone (void)
523 //  Get Machine Timezone.
524 ////////////////////////////////////////////////////////////////////////////
525 int
526 TermWindow::GetTimeZone ()
527 {
528   struct timeval tv;
529   struct timezone tm;
530 
531   gettimeofday (&tv, &tm);
532 
533   return -tm.tz_minuteswest / 60;
534 }
535 
536 ////////////////////////////////////////////////////////////////////////////
537 // void SetWindowTitle (void)
538 // set window title bar (pty device name, and coding)
539 ////////////////////////////////////////////////////////////////////////////
540 
541 #include "spawn.h"
542 
543 void
544 TermWindow::SetWindowTitle (void)
545 {
546   char windowname[256];
547   sprintf(windowname, gWindowName);
548   this->SetTitle (windowname);
549 
550 }
551 ////////////////////////////////////////////////////////////////////////////
552 // GetSupoprtedSuites (BMessage *)
553 //
554 ////////////////////////////////////////////////////////////////////////////
555 void
556 TermWindow::TermWinActivate (void)
557 {
558 
559   this->Activate();
560 
561   if (focus_follows_mouse()) {
562     BPoint aMouseLoc = this->Frame().LeftTop();
563     set_mouse_position(int32(aMouseLoc.x + 16), int32(aMouseLoc.y + 2));
564     be_app->SetCursor(B_HAND_CURSOR);
565   }
566 }
567 
568 ////////////////////////////////////////////////////////////////////////////
569 // GetSupoprtedSuites (BMessage *)
570 //
571 ////////////////////////////////////////////////////////////////////////////
572 status_t
573 TermWindow::GetSupportedSuites(BMessage *msg)
574 {
575   static property_info prop_list[] = {
576      { "encode",
577        {B_GET_PROPERTY, 0},
578        {B_DIRECT_SPECIFIER, 0},
579        "get muterminal encode"},
580      { "encode",
581        {B_SET_PROPERTY, 0},
582        {B_DIRECT_SPECIFIER, 0},
583        "set muterminal encode"},
584      { "tty",
585        {B_GET_PROPERTY, 0},
586        {B_DIRECT_SPECIFIER, 0},
587        "get tty_name."},
588      { 0  }
589 
590   };
591   msg->AddString("suites", "suite/vnd.naan-termwindow");
592   BPropertyInfo prop_info(prop_list);
593   msg->AddFlat("messages", &prop_info);
594   return BWindow::GetSupportedSuites(msg);
595 }
596 ////////////////////////////////////////////////////////////////////////////
597 // ResolveSpecifier
598 //
599 ////////////////////////////////////////////////////////////////////////////
600 BHandler*
601 TermWindow::ResolveSpecifier(BMessage *msg, int32 index,
602            BMessage *specifier, int32 form,
603            const char *property)
604 {
605   if ( (strcmp(property, "encode") == 0)
606     && ((msg->what == B_SET_PROPERTY) || (msg->what == B_GET_PROPERTY) ))
607       return this;
608   else if ( (strcmp(property, "tty") == 0)
609     &&  (msg->what == B_GET_PROPERTY) )
610       return this;
611 
612   return BWindow::ResolveSpecifier(msg, index, specifier, form, property);
613 }
614 
615 ////////////////////////////////////////////////////////////////////////////
616 // SetCoding
617 //  Set coding utility functions.
618 ////////////////////////////////////////////////////////////////////////////
619 void SetCoding (int coding)
620 {
621   const etable *p = encoding_table;
622   p += coding;
623 
624   gNowCoding = coding;
625 
626   return;
627 }
628 ////////////////////////////////////////////////////////////////////////////
629 // DoPageSetUp ()
630 //
631 ////////////////////////////////////////////////////////////////////////////
632 status_t
633 TermWindow::DoPageSetup()
634 {
635   status_t rv;
636   BPrintJob job("PageSetup");
637 
638   /* display the page configure panel */
639   rv = job.ConfigPage();
640 
641   /* save a pointer to the settings */
642   fPrintSettings = job.Settings();
643 
644   return rv;
645 }
646 
647 ////////////////////////////////////////////////////////////////////////////
648 // DoPrint ()
649 //
650 ////////////////////////////////////////////////////////////////////////////
651 void
652 TermWindow::DoPrint()
653 {
654 //#if B_BEOS_VERSION < 0x0460
655   BPrintJob job("Print");
656 
657   if((! fPrintSettings) && (DoPageSetup() != B_NO_ERROR)) {
658     (new BAlert("Cancel", "Print cancelled.", "OK"))->Go();
659   return;
660   }
661 
662   job.SetSettings(new BMessage(*fPrintSettings));
663 
664   BRect pageRect = job.PrintableRect();
665   BRect curPageRect = pageRect;
666 
667   int pHeight = (int)pageRect.Height();
668   int pWidth = (int)pageRect.Width();
669   float w,h;
670   fTermView->GetFrameSize (&w, &h);
671   int xPages = (int)ceil(w / pWidth);
672   int yPages = (int)ceil(h / pHeight);
673 
674    /* engage the print server */
675   job.BeginJob();
676 
677   /* loop through and draw each page, and write to spool */
678   for(int x = 0; x < xPages; x++)
679     for(int y = 0; y < yPages; y++){
680       curPageRect.OffsetTo(x * pWidth, y * pHeight);
681       job.DrawView(fTermView, curPageRect, BPoint(0, 0));
682       job.SpoolPage();
683 
684       if(!job.CanContinue()){
685       	  // It is likely that the only way that the job was cancelled is
686       	  // because the user hit 'Cancel' in the page setup window, in which
687       	  // case, the user does *not* need to be told that it was cancelled.
688       	  // He/she will simply expect that it was done.
689 //        (new BAlert("Cancel", "Print job cancelled", "OK"))->Go();
690         return;
691       }
692   }
693 
694   /* commit the job, send the spool file */
695   job.CommitJob();
696 //#endif
697 }
698