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