1/* 2 copyright 2002, 2003 Alexander Malmberg <alexander@malmberg.org> 3 4 2009-2016 GAP Project 5 6 Authors: Alexander Malmberg <alexander@malmberg.org> 7 Riccardo Mottola 8 Tim Sheridan 9 10 This program is free software; you can redistribute it and/or modify 11 it under the terms of the GNU General Public License as published by 12 the Free Software Foundation; version 2 of the License. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program; if not, write to the Free Software 21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22*/ 23 24#import <Foundation/NSAutoreleasePool.h> 25#import <Foundation/NSString.h> 26#import <Foundation/NSBundle.h> 27#import <Foundation/NSDebug.h> 28#import <Foundation/NSNotification.h> 29#import <Foundation/NSProcessInfo.h> 30#import <Foundation/NSRunLoop.h> 31#import <Foundation/NSUserDefaults.h> 32#import <Foundation/NSDictionary.h> 33#import <AppKit/NSApplication.h> 34#import <AppKit/NSControl.h> 35#import <AppKit/NSEvent.h> 36#import <AppKit/NSMenu.h> 37#import <AppKit/NSMenuItem.h> 38#import <AppKit/NSPanel.h> 39#import <AppKit/NSView.h> 40 41/* For the quit panel: */ 42#import <AppKit/NSTextField.h> 43#import <AppKit/NSButton.h> 44#import <AppKit/NSImage.h> 45#import <AppKit/NSImageView.h> 46#import <AppKit/NSScreen.h> 47#import <AppKit/NSBox.h> 48#import <GNUstepGUI/GSVbox.h> 49#import <GNUstepGUI/GSHbox.h> 50#import "Label.h" 51 52 53#import "PreferencesWindowController.h" 54#import "Services.h" 55#import "ServicesPrefs.h" 56#import "TerminalView.h" 57#import "TerminalViewPrefs.h" 58#import "TerminalWindow.h" 59#import "TerminalWindowPrefs.h" 60#import "TerminalParser_LinuxPrefs.h" 61 62@interface NSMenu (helpers) 63-(id <NSMenuItem>) addItemWithTitle: (NSString *)s; 64-(id <NSMenuItem>) addItemWithTitle: (NSString *)s action: (SEL)sel; 65@end 66@implementation NSMenu (im_lazy) 67-(id <NSMenuItem>) addItemWithTitle: (NSString *)s 68{ 69 return [self addItemWithTitle: s action: NULL keyEquivalent: nil]; 70} 71 72-(id <NSMenuItem>) addItemWithTitle: (NSString *)s action: (SEL)sel 73{ 74 return [self addItemWithTitle: s action: sel keyEquivalent: nil]; 75} 76@end 77 78 79@interface Terminal : NSObject 80{ 81 PreferencesWindowController *pwc; 82 83 NSPanel *quitPanel; 84 BOOL quitPanelOpen; 85} 86 87@end 88 89@implementation Terminal 90 91- init 92{ 93 if (!(self=[super init])) return nil; 94 return self; 95} 96 97-(void) dealloc 98{ 99 [[NSNotificationCenter defaultCenter] 100 removeObserver: self]; 101 102 DESTROY(pwc); 103 [super dealloc]; 104} 105 106 107-(void) openPreferences: (id)sender 108{ 109 if (!pwc) 110 { 111 NSObject<PrefBox> *pb; 112 pwc=[[PreferencesWindowController alloc] init]; 113 114 pb=[[TerminalViewDisplayPrefs alloc] init]; 115 [pwc addPrefBox: pb]; 116 DESTROY(pb); 117 118 pb=[[TerminalViewShellPrefs alloc] init]; 119 [pwc addPrefBox: pb]; 120 DESTROY(pb); 121 122 pb=[[TerminalViewKeyboardPrefs alloc] init]; 123 [pwc addPrefBox: pb]; 124 DESTROY(pb); 125 126 pb=[[TerminalWindowPrefs alloc] init]; 127 [pwc addPrefBox: pb]; 128 DESTROY(pb); 129 130 pb=[[TerminalServicesPrefs alloc] init]; 131 [pwc addPrefBox: pb]; 132 DESTROY(pb); 133 134 pb=[[TerminalParser_LinuxPrefs alloc] init]; 135 [pwc addPrefBox: pb]; 136 DESTROY(pb); 137 } 138 [pwc showWindow: self]; 139} 140 141 142-(void) applicationWillTerminate: (NSNotification *)n 143{ 144} 145 146 147-(void) applicationWillFinishLaunching: (NSNotification *)n 148{ 149 NSMenu *menu,*m/*,*m2*/; 150 151 [TerminalView registerPasteboardTypes]; 152 153 menu=[[NSMenu alloc] init]; 154 155 /* 'Info' menu */ 156 m=[[NSMenu alloc] init]; 157 [m addItemWithTitle: _(@"Info...") 158 action: @selector(orderFrontStandardInfoPanel:)]; 159 [m addItemWithTitle: _(@"Preferences...") 160 action: @selector(openPreferences:)]; 161 [m addItemWithTitle: _(@"Benchmark") 162 action: @selector(benchmark:)]; 163 [menu setSubmenu: m forItem: [menu addItemWithTitle: _(@"Info")]]; 164 [m release]; 165 166 /* 'Terminal' menu */ 167 m=[[NSMenu alloc] init]; 168 [m addItemWithTitle: _(@"New window") 169 action: @selector(openWindow:) 170 keyEquivalent: @"n"]; 171 [m addItemWithTitle: _(@"New tab") 172 action: @selector(openTab:) 173 keyEquivalent: @"t"]; 174 [menu setSubmenu: m forItem: [menu addItemWithTitle: _(@"Shell")]]; 175 [m release]; 176 177 178 /* 'Edit' menu */ 179 m=[[NSMenu alloc] init]; 180 [m addItemWithTitle: _(@"Cut") 181 action: @selector(cut:) 182 keyEquivalent: @"x"]; 183 [m addItemWithTitle: _(@"Copy") 184 action: @selector(copy:) 185 keyEquivalent: @"c"]; 186 [m addItemWithTitle: _(@"Paste") 187 action: @selector(paste:) 188 keyEquivalent: @"v"]; 189 [menu setSubmenu: m forItem: [menu addItemWithTitle: _(@"Edit")]]; 190 [m release]; 191 192 /* 'View' menu */ 193 m=[[NSMenu alloc] init]; 194 [m addItemWithTitle: _(@"Show tab bar") 195 action: @selector(showTabBarToggle:) 196 keyEquivalent: @"T"]; 197 [menu setSubmenu: m forItem: [menu addItemWithTitle: _(@"View")]]; 198 [m release]; 199 200 /* 'Windows' menu */ 201 m=[[NSMenu alloc] init]; 202 [m addItemWithTitle: _(@"Close window") 203 action: @selector(performClose:) 204 keyEquivalent: @"W"]; 205 [m addItemWithTitle: _(@"Close tab") 206 action: @selector(closeTab:) 207 keyEquivalent: @"w"]; 208 [m addItemWithTitle: _(@"Show previous tab") 209 action: @selector(showPreviousTab:) 210 keyEquivalent: @"{"]; 211 [m addItemWithTitle: _(@"Show next tab") 212 action: @selector(showNextTab:) 213 keyEquivalent: @"}"]; 214 [m addItemWithTitle: _(@"Move tab left") 215 action: @selector(moveTabLeft:) 216 keyEquivalent: @"("]; 217 [m addItemWithTitle: _(@"Move tab right") 218 action: @selector(moveTabRight:) 219 keyEquivalent: @")"]; 220 [m addItemWithTitle: _(@"Miniaturize all") 221 action: @selector(miniaturizeAll:) 222 keyEquivalent: @"m"]; 223 [menu setSubmenu: m forItem: [menu addItemWithTitle: _(@"Windows")]]; 224 [NSApp setWindowsMenu: m]; 225 [m release]; 226 227 m=[[NSMenu alloc] init]; 228 [menu setSubmenu: m forItem: [menu addItemWithTitle: _(@"Services")]]; 229 [NSApp setServicesMenu: m]; 230 [m release]; 231 232 [menu addItemWithTitle: _(@"Hide") 233 action: @selector(hide:) 234 keyEquivalent: @"h"]; 235 236 [menu addItemWithTitle: _(@"Quit") 237 action: @selector(terminate:) 238 keyEquivalent: @"q"]; 239 240 [NSApp setMainMenu: menu]; 241 [menu release]; 242 243 [[NSNotificationCenter defaultCenter] 244 addObserver: self 245 selector: @selector(noMoreActiveWindows:) 246 name: TerminalWindowNoMoreActiveWindowsNotification 247 object: nil]; 248} 249 250-(void) openWindow: (id)sender 251{ 252 TerminalWindowController *twc; 253 twc=[TerminalWindowController newTerminalWindow]; 254 [[twc frontTerminalView] runShell]; 255} 256 257-(void) openTab: (id)sender 258{ 259 TerminalWindowController *twc = [[NSApp keyWindow] windowController]; 260 [twc newTerminalTabInWindow:[NSApp keyWindow]]; 261 [[twc frontTerminalView] runShell]; 262} 263 264-(void) closeTab: (id)sender 265{ 266 TerminalWindowController *twc = [[NSApp keyWindow] windowController]; 267 TerminalView *tv = [twc frontTerminalView]; 268 [twc closeTerminalTab:tv inWindow:[NSApp keyWindow]]; 269} 270 271-(void) showTabBarToggle: (id)sender 272{ 273 TerminalWindowController *twc = [[NSApp keyWindow] windowController]; 274 [twc setShowTabBar:(! [twc showTabBar]) inWindow:[NSApp keyWindow]]; 275} 276 277-(void) showPreviousTab: (id)sender 278{ 279 TerminalWindowController *twc = [[NSApp keyWindow] windowController]; 280 [twc showPreviousTab]; 281} 282 283-(void) showNextTab: (id)sender 284{ 285 TerminalWindowController *twc = [[NSApp keyWindow] windowController]; 286 [twc showNextTab]; 287} 288 289-(void) moveTabLeft: (id)sender 290{ 291 TerminalWindowController *twc = [[NSApp keyWindow] windowController]; 292 [twc moveTabLeft]; 293} 294 295-(void) moveTabRight: (id)sender 296{ 297 TerminalWindowController *twc = [[NSApp keyWindow] windowController]; 298 [twc moveTabRight]; 299} 300 301 302-(void) applicationDidFinishLaunching: (NSNotification *)n 303{ 304 NSArray *args=[[NSProcessInfo processInfo] arguments]; 305 306 [TerminalServices updateServicesPlist]; 307 308 [NSApp setServicesProvider: [[TerminalServices alloc] init]]; 309 310 if ([args count]>1) 311 { 312 TerminalWindowController *twc; 313 NSString *cmdline; 314 315 args=[args subarrayWithRange: NSMakeRange(1,[args count]-1)]; 316 cmdline=[args componentsJoinedByString: @" "]; 317 318 twc=[TerminalWindowController newTerminalWindow]; 319 [[twc frontTerminalView] runProgram: @"/bin/sh" 320 withArguments: [NSArray arrayWithObjects: @"-c",cmdline,nil] 321 initialInput: nil]; 322 [twc release]; 323 } 324 else 325 [self openWindow: self]; 326} 327 328 329-(NSApplicationTerminateReply) applicationShouldTerminate: (NSApplication *)sender 330{ 331 if (![TerminalWindowController numberOfActiveWindows]) 332 return NSTerminateNow; 333 334 if (!quitPanel) 335 { 336 NSButton *b_quit,*b_dont; 337 338 { 339 GSVbox *vb=[[GSVbox alloc] init]; 340 341 [vb setBorder: 10.0]; 342 343 { 344 NSButton *butt; 345 GSHbox *hb; 346 347 hb=[[GSHbox alloc] init]; 348 [hb setAutoresizingMask: NSViewMinXMargin]; 349 350 butt=b_quit=[[NSButton alloc] init]; 351 [butt setTitle: _(@"Quit anyway")]; 352 [butt setTarget: self]; 353 [butt setAction: @selector(quitAnyway:)]; 354 [butt sizeToFit]; 355 [hb addView: butt enablingXResizing: NO]; 356 DESTROY(butt); 357 358 butt=b_dont=[[NSButton alloc] init]; 359 [butt setTitle: _(@"Don't quit")]; 360 [butt setImagePosition: NSImageRight]; 361 [butt setImage: [NSImage imageNamed: @"common_ret"]]; 362 [butt setTarget: self]; 363 [butt setAction: @selector(dontQuit:)]; 364 [butt sizeToFit]; 365 [hb addView: butt enablingXResizing: NO withMinXMargin: 8.0]; 366 DESTROY(butt); 367 368 [vb addView: hb enablingYResizing: NO]; 369 DESTROY(hb); 370 } 371 372 { 373 NSTextField *text; 374 375 text=[NSTextField newLabel: 376 _(@"There are active windows. Quitting will close them.")]; 377 [text setAutoresizingMask: NSViewWidthSizable|NSViewMinYMargin]; 378 [text sizeToFit]; 379 380 [vb addView: text enablingYResizing: YES withMinYMargin: 8.0]; 381 DESTROY(text); 382 } 383 384 [vb addSeparatorWithMinYMargin: 8.0]; 385 386 { 387 NSImageView *iv; 388 NSTextField *title; 389 GSHbox *hb; 390 391 hb=[[GSHbox alloc] init]; 392 393 iv=[[NSImageView alloc] init]; 394 [iv setImage: [NSApp applicationIconImage]]; 395 [iv setEditable: NO]; 396 [iv sizeToFit]; 397 [hb addView: iv enablingXResizing: NO]; 398 DESTROY(iv); 399 400 title=[NSTextField newLabel: _(@"Quit?")]; 401 [title setAutoresizingMask: NSViewMinYMargin|NSViewMaxYMargin]; 402 [title setFont: [NSFont systemFontOfSize: 18.0]]; 403 [title sizeToFit]; 404 [hb addView: title enablingXResizing: NO withMinXMargin: 8.0]; 405 DESTROY(title); 406 407 [vb addView: hb enablingYResizing: NO withMinYMargin: 8.0]; 408 DESTROY(hb); 409 } 410 411 [vb sizeToFit]; 412 413 quitPanel=[[NSPanel alloc] initWithContentRect: [vb frame] 414 styleMask: NSTitledWindowMask 415 backing: NSBackingStoreRetained 416 defer: YES]; 417 [quitPanel setContentView: vb]; 418 DESTROY(vb); 419 } 420 421 [quitPanel setTitle: _(@"Quit?")]; 422 [quitPanel setOneShot: YES]; 423 [quitPanel setHidesOnDeactivate: NO]; 424 [quitPanel setExcludedFromWindowsMenu: NO]; 425 426 [quitPanel setInitialFirstResponder: b_dont]; 427 [b_dont setNextKeyView: b_quit]; 428 [b_quit setNextKeyView: b_dont]; 429 } 430 431 { 432 /* TODO: always using +mainScreen is probably incorrect */ 433 NSRect r=[[NSScreen mainScreen] frame]; 434 NSPoint o; 435 436 o.x=r.origin.x+r.size.width/2.0-[quitPanel frame].size.width/2.0; 437 o.y=r.origin.y+r.size.height/2.0-[quitPanel frame].size.height/2.0; 438 [quitPanel setFrameOrigin: o]; 439 } 440 441 [quitPanel setExcludedFromWindowsMenu: NO]; 442 [quitPanel makeKeyAndOrderFront: self]; 443 quitPanelOpen=YES; 444 445 return NSTerminateLater; 446} 447 448-(void) quitAnyway: (id)sender 449{ 450 [NSApp replyToApplicationShouldTerminate: YES]; 451} 452 453-(void) dontQuit: (id)sender 454{ 455 [NSApp replyToApplicationShouldTerminate: NO]; 456 quitPanelOpen=NO; 457 [quitPanel orderOut: self]; 458 [quitPanel setExcludedFromWindowsMenu: YES]; 459} 460 461-(void) noMoreActiveWindows: (NSNotification *)n 462{ 463 if (quitPanelOpen) 464 [NSApp replyToApplicationShouldTerminate: YES]; 465} 466 467 468-(BOOL) application: (NSApplication *)sender 469 openFile: (NSString *)filename 470{ 471 TerminalWindowController *twc; 472 473 NSDebugLLog(@"Application",@"openFile: '%@'",filename); 474 475 /* TODO: shouldn't ignore other apps */ 476 [NSApp activateIgnoringOtherApps: YES]; 477 478 twc=[TerminalWindowController newTerminalWindow]; 479 [[twc frontTerminalView] runProgram: filename 480 withArguments: nil 481 initialInput: nil]; 482 483 return YES; 484} 485 486 487 488-(BOOL) terminalRunProgram: (NSString *)path 489 withArguments: (NSArray *)args 490 inDirectory: (NSString *)directory 491 properties: (NSDictionary *)properties 492{ 493 TerminalWindowController *twc; 494 495 NSDebugLLog(@"Application", 496 @"terminalRunProgram: %@ withArguments: %@ inDirectory: %@ properties: %@", 497 path,args,directory,properties); 498 499 /* TODO: shouldn't ignore other apps */ 500 [NSApp activateIgnoringOtherApps: YES]; 501 502 { 503 id o; 504 o=[properties objectForKey: @"CloseOnExit"]; 505 if (o && [o respondsToSelector: @selector(boolValue)] && 506 ![o boolValue]) 507 { 508 twc=[TerminalWindowController idleTerminalWindow]; 509 } 510 else 511 { 512 twc=[TerminalWindowController newTerminalWindow]; 513 } 514 } 515 516 [[twc frontTerminalView] runProgram: path 517 withArguments: args 518 inDirectory: directory 519 initialInput: nil 520 arg0: nil]; 521 522 return YES; 523} 524 525-(BOOL) terminalRunCommand: (NSString *)cmdline 526 inDirectory: (NSString *)directory 527 properties: (NSDictionary *)properties 528{ 529 NSDebugLLog(@"Application", 530 @"terminalRunCommand: %@ inDirectory: %@ properties: %@", 531 cmdline,directory,properties); 532 533 return [self terminalRunProgram: @"/bin/sh" 534 withArguments: [NSArray arrayWithObjects: @"-c",cmdline,nil] 535 inDirectory: directory 536 properties: properties]; 537} 538 539 540@end 541 542 543/* TODO */ 544 545#include <AppKit/NSWindow.h> 546#include <AppKit/NSEvent.h> 547 548@interface NSWindow (avoid_warnings) 549-(void) sendEvent: (NSEvent *)e; 550@end 551 552 553@interface TerminalApplication : NSApplication 554@end 555 556@implementation TerminalApplication 557-(void) sendEvent: (NSEvent *)e 558{ 559 if ([e type]==NSKeyDown && [e modifierFlags]&NSCommandKeyMask && 560 [TerminalViewKeyboardPrefs commandAsMeta]) 561 { 562 NSDebugLLog(@"key",@"intercepting key equivalent"); 563 [[e window] sendEvent: e]; 564 return; 565 } 566 [super sendEvent: e]; 567} 568@end 569 570 571int main(int argc, char **argv) 572{ 573 Terminal *term; 574 575 CREATE_AUTORELEASE_POOL(arp); 576 577/* [NSObject enableDoubleReleaseCheck: YES];*/ 578 579 [TerminalApplication sharedApplication]; 580 581 term = [[Terminal alloc] init]; 582 [NSApp setDelegate: term]; 583 [NSApp run]; 584 585 [term release]; 586 587 DESTROY(arp); 588 return 0; 589} 590 591