diff options
Diffstat (limited to 'xc/programs/Xserver/hw/darwin/bundle/Xserver.m')
-rw-r--r-- | xc/programs/Xserver/hw/darwin/bundle/Xserver.m | 299 |
1 files changed, 228 insertions, 71 deletions
diff --git a/xc/programs/Xserver/hw/darwin/bundle/Xserver.m b/xc/programs/Xserver/hw/darwin/bundle/Xserver.m index 405e91250..152d896d8 100644 --- a/xc/programs/Xserver/hw/darwin/bundle/Xserver.m +++ b/xc/programs/Xserver/hw/darwin/bundle/Xserver.m @@ -6,12 +6,14 @@ // // Created by Andreas Monitzer on January 6, 2001. // -/* $XFree86: xc/programs/Xserver/hw/darwin/bundle/Xserver.m,v 1.18 2001/05/16 06:10:08 torrey Exp $ */ +/* $XFree86: xc/programs/Xserver/hw/darwin/bundle/Xserver.m,v 1.22 2001/08/07 02:40:36 torrey Exp $ */ #import "Xserver.h" #import "Preferences.h" #import "quartzShared.h" +#import "XWindow.h" + // Macros to build the path name #ifndef XBINDIR #define XBINDIR /usr/X11R6/bin @@ -31,29 +33,36 @@ static NSPortMessage *signalMessage; @implementation Xserver -- (id)init { +- (id)init +{ self=[super init]; serverLock = [[NSLock alloc] init]; clientTask = nil; + serverRunning = NO; serverVisible = NO; + rootlessMenuBarVisible = YES; appQuitting = NO; mouseState = 0; eventWriteFD = quartzEventWriteFD; // set up a port to safely send messages to main thread from server thread signalPort = [[NSPort port] retain]; - signalMessage = [[NSPortMessage alloc] initWithSendPort:signalPort receivePort:signalPort components:nil]; + signalMessage = [[NSPortMessage alloc] initWithSendPort:signalPort + receivePort:signalPort components:nil]; // set up receiving end [signalPort setDelegate:self]; - [[NSRunLoop currentRunLoop] addPort:signalPort forMode:NSDefaultRunLoopMode]; - [[NSRunLoop currentRunLoop] addPort:signalPort forMode:NSModalPanelRunLoopMode]; + [[NSRunLoop currentRunLoop] addPort:signalPort + forMode:NSDefaultRunLoopMode]; + [[NSRunLoop currentRunLoop] addPort:signalPort + forMode:NSModalPanelRunLoopMode]; return self; } -- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender { +- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender +{ // Quit if the X server is not running if ([serverLock tryLock]) return NSTerminateNow; @@ -84,25 +93,52 @@ static NSPortMessage *signalMessage; } // returns YES when event was handled -- (BOOL)translateEvent:(NSEvent *)anEvent { +- (BOOL)translateEvent:(NSEvent *)anEvent +{ NXEvent ev; + static BOOL mouse1Pressed = NO; + unsigned int adjustedModifiers; - if(([anEvent type]==NSKeyDown) && (![anEvent isARepeat]) && - ([anEvent keyCode]==[Preferences keyCode]) && - ([anEvent modifierFlags]==[Preferences modifiers])) { + if (!serverRunning) + return NO; + + // Check for switch keypress + // Ignore caps lock iff the swich key preference does not use caps lock. + if ([Preferences modifiers] & NSAlphaShiftKeyMask) { + adjustedModifiers = [anEvent modifierFlags]; + } else { + adjustedModifiers = [anEvent modifierFlags] & ~NSAlphaShiftKeyMask; + } + if (([anEvent type] == NSKeyDown) && (![anEvent isARepeat]) && + ([anEvent keyCode] == [Preferences keyCode]) && + (adjustedModifiers == [Preferences modifiers])) + { [self toggle]; return YES; } - if(!serverVisible) + if(!serverVisible && !quartzRootless) return NO; [self getNXMouse:&ev]; ev.type=[anEvent type]; ev.flags=[anEvent modifierFlags]; switch(ev.type) { - case NSLeftMouseDown: case NSLeftMouseUp: + if (quartzRootless && !mouse1Pressed) { + // MouseUp after MouseDown in menu - ignore + return NO; + } + mouse1Pressed = NO; + break; + case NSLeftMouseDown: + if (quartzRootless && + ! ([anEvent window] && + [[anEvent window] isKindOfClass:[XWindow class]])) { + // Click in non X window - ignore + return NO; + } + mouse1Pressed = YES; case NSMouseMoved: break; case NSLeftMouseDragged: @@ -142,13 +178,29 @@ static NSPortMessage *signalMessage; [self sendNXEvent:&ev]; + // Rootless: Send first NSLeftMouseDown to windows and views so window + // ordering can be suppressed. + // Don't pass further events - they (incorrectly?) bring the window + // forward no matter what. + if (quartzRootless && + ([anEvent type]==NSLeftMouseDown || [anEvent type]==NSLeftMouseUp) && + [anEvent clickCount] == 1 && + [anEvent window] && + [[anEvent window] isKindOfClass:[XWindow class]]) + { + return NO; + } + return YES; } -- (void)getNXMouse:(NXEvent*)ev { +// Fill in NXEvent with mouse coordinates, inverting y coordinate +- (void)getNXMouse:(NXEvent*)ev +{ NSPoint pt=[NSEvent mouseLocation]; + ev->location.x=(int)(pt.x); - ev->location.y=[[NSScreen mainScreen] frame].size.height-(int)(pt.y); // invert mouse + ev->location.y=[[NSScreen mainScreen] frame].size.height - (int)(pt.y); } // Append a string to the given enviroment variable @@ -158,13 +210,46 @@ static NSPortMessage *signalMessage; stringByAppendingString:value] cString],1); } -- (void)applicationDidFinishLaunching:(NSNotification *)aNotification { - // Start the X server thread - [NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil]; +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification +{ + // Block SIGPIPE + // SIGPIPE repeatably killed the (rootless) server when closing a + // dozen xterms in rapid succession. Those SIGPIPEs should have been + // sent to the X server thread, which ignores them, but somehow they + // ended up in this thread instead. + { + sigset_t set; + sigemptyset(&set); + sigaddset(&set, SIGPIPE); + // pthread_sigmask not implemented yet + // pthread_sigmask(SIG_BLOCK, &set, NULL); + sigprocmask(SIG_BLOCK, &set, NULL); + } - // If we are going to display a splash screen, hide the X11 screen immediately - if ([Preferences startupHelp]) - [self sendShowHide:NO]; + if (quartzRootless == -1) { + // The display mode was not set from the command line. + // Show mode pick panel? + if ([Preferences modeWindow]) { + [modeWindow makeKeyAndOrderFront:nil]; + } else { + // Otherwise use default mode + quartzRootless = [Preferences rootless]; + [self startX]; + } + } else { + [self startX]; + } +} + +// Start the X server thread and the client process +- (void)startX +{ + [modeWindow close]; + + // Start the X server thread + [NSThread detachNewThreadSelector:@selector(run) toTarget:self + withObject:nil]; + serverRunning = YES; // Start the X clients if started from GUI if (quartzStartClients) { @@ -177,9 +262,9 @@ static NSPortMessage *signalMessage; NSArray *args; // Register to receive notification when the client task finishes - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(clientTaskDone:) - name:NSTaskDidTerminateNotification + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(clientTaskDone:) + name:NSTaskDidTerminateNotification object:nil]; // Change to user's home directory (so xterms etc. start there) @@ -217,24 +302,33 @@ static NSPortMessage *signalMessage; clientTask = [NSTask launchedTaskWithLaunchPath:path arguments:args]; } - // Make sure the menu bar gets drawn - [NSApp setWindowsNeedUpdate:YES]; - - // Show the X switch window if not using dock icon switching - if (![Preferences dockSwitch]) - [switchWindow orderFront:nil]; - - // Display the help splash screen or show the X server - if ([Preferences startupHelp]) { - [helpWindow makeKeyAndOrderFront:nil]; + if (quartzRootless) { + // There is no help window for rootless; just start + [helpWindow close]; + if ([NSApp isActive]) + [self sendShowHide:YES]; + else + [self sendShowHide:NO]; } else { - ShowMenuBar(); - [self closeHelpAndShow:nil]; + // Show the X switch window if not using dock icon switching + if (![Preferences dockSwitch]) + [switchWindow orderFront:nil]; + + if ([Preferences startupHelp]) { + // display the full screen mode help + [self sendShowHide:NO]; + [helpWindow makeKeyAndOrderFront:nil]; + } else { + // start running full screen and make sure X is visible + ShowMenuBar(); + [self closeHelpAndShow:nil]; + } } } // Run the X server thread -- (void)run { +- (void)run +{ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; [serverLock lock]; @@ -245,14 +339,32 @@ static NSPortMessage *signalMessage; QuartzMessageMainThread(kQuartzServerDied); } -// Close the help splash screen and show the X server -- (IBAction)closeHelpAndShow:(id)sender { - int helpVal; +// Full screen mode was picked in the mode pick panel +- (IBAction)startFullScreen:(id)sender +{ + [Preferences setModeWindow:[startupModeButton intValue]]; + [Preferences saveToDisk]; + quartzRootless = FALSE; + [self startX]; +} - helpVal = [startupHelpButton intValue]; - [Preferences setStartupHelp:helpVal]; +// Rootless mode was picked in the mode pick panel +- (IBAction)startRootless:(id)sender +{ + [Preferences setModeWindow:[startupModeButton intValue]]; [Preferences saveToDisk]; + quartzRootless = TRUE; + [self startX]; +} +// Close the help splash screen and show the X server +- (IBAction)closeHelpAndShow:(id)sender +{ + if (sender) { + int helpVal = [startupHelpButton intValue]; + [Preferences setStartupHelp:helpVal]; + [Preferences saveToDisk]; + } [helpWindow close]; serverVisible = YES; @@ -261,34 +373,48 @@ static NSPortMessage *signalMessage; } // Show the X server when sent message from GUI -- (IBAction)showAction:(id)sender { - [self sendShowHide:YES]; +- (IBAction)showAction:(id)sender +{ + if (serverRunning) + [self sendShowHide:YES]; } -// Show or hide the X server -- (void)toggle { - if (serverVisible) - [self hide]; - else - [self show]; +// Show or hide the X server or menu bar in rootless mode +- (void)toggle +{ + if (quartzRootless) { + if (rootlessMenuBarVisible) + HideMenuBar(); + else + ShowMenuBar(); + rootlessMenuBarVisible = !rootlessMenuBarVisible; + } else { + if (serverVisible) + [self hide]; + else + [self show]; + } } // Show the X server on screen -- (void)show { - if (!serverVisible) { +- (void)show +{ + if (!serverVisible && serverRunning) { [self sendShowHide:YES]; } } // Hide the X server from the screen -- (void)hide { - if (serverVisible) { +- (void)hide +{ + if (serverVisible && serverRunning) { [self sendShowHide:NO]; } } // Kill the Xserver thread -- (void)killServer { +- (void)killServer +{ NXEvent ev; if (serverVisible) @@ -301,15 +427,18 @@ static NSPortMessage *signalMessage; // Tell the X server to show or hide itself. // This ignores the current X server visible state. -- (void)sendShowHide:(BOOL)show { +- (void)sendShowHide:(BOOL)show +{ NXEvent ev; [self getNXMouse:&ev]; ev.type = NX_APPDEFINED; if (show) { - QuartzCapture(); - HideMenuBar(); + if (!quartzRootless) { + QuartzCapture(); + HideMenuBar(); + } ev.data.compound.subType = kXDarwinShow; [self sendNXEvent:&ev]; @@ -326,14 +455,15 @@ static NSPortMessage *signalMessage; ev.data.compound.subType = kXDarwinHide; [self sendNXEvent:&ev]; - ShowMenuBar(); + if (!quartzRootless) + ShowMenuBar(); } serverVisible = show; } // Tell the X server to read from the pasteboard into the X cut buffer -- (void)readPasteboard +- (void)readPasteboard { NXEvent ev; @@ -343,7 +473,7 @@ static NSPortMessage *signalMessage; } // Tell the X server to write the X cut buffer into the pasteboard -- (void)writePasteboard +- (void)writePasteboard { NXEvent ev; @@ -352,15 +482,32 @@ static NSPortMessage *signalMessage; [self sendNXEvent:&ev]; } -- (void)sendNXEvent:(NXEvent*)ev { - if (write(eventWriteFD, ev, sizeof(*ev)) == sizeof(*ev)) +- (void)sendNXEvent:(NXEvent*)ev +{ + int bytesWritten; + + if (quartzRootless && + (ev->type == NSLeftMouseDown || ev->type == NSLeftMouseUp || + (ev->type == NSSystemDefined && ev->data.compound.subType == 7))) + { + // mouse button event - send mouseMoved to this position too + // X gets confused if it gets a click that isn't at the last + // reported mouse position. + NXEvent moveEvent = *ev; + moveEvent.type = NSMouseMoved; + [self sendNXEvent:&moveEvent]; + } + + bytesWritten = write(eventWriteFD, ev, sizeof(*ev)); + if (bytesWritten == sizeof(*ev)) return; NSLog(@"Bad write to event pipe."); // FIXME: handle bad writes better? } // Handle messages from the X server thread -- (void)handlePortMessage:(NSPortMessage *)portMessage { +- (void)handlePortMessage:(NSPortMessage *)portMessage +{ unsigned msg = [portMessage msgid]; switch(msg) { @@ -370,6 +517,7 @@ static NSPortMessage *signalMessage; [NSCursor unhide]; break; case kQuartzServerDied: + serverRunning = NO; if (appQuitting) { // If we quit before the clients start, they may sit and wait // for the X server to start. Kill them instead. @@ -386,7 +534,8 @@ static NSPortMessage *signalMessage; } // Quit the X server when the X client task finishes -- (void)clientTaskDone:(NSNotification *)aNotification { +- (void)clientTaskDone:(NSNotification *)aNotification +{ // Make sure it was the client task that finished if (![clientTask isRunning]) { int status = [[aNotification object] terminationStatus]; @@ -399,20 +548,27 @@ static NSPortMessage *signalMessage; } } -// Called when the user clicks the application icon, but not when Cmd-Tab is used -- (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)flag { - if ([Preferences dockSwitch]) { +// Called when the user clicks the application icon, +// but not when Cmd-Tab is used. +// Rootless: Don't switch until applicationWillBecomeActive. +- (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication + hasVisibleWindows:(BOOL)flag +{ + if ([Preferences dockSwitch] && !quartzRootless) { [self show]; } return NO; } -- (void)applicationWillResignActive:(NSNotification *)aNotification { +- (void)applicationWillResignActive:(NSNotification *)aNotification +{ [self hide]; } -- (void)applicationWillBecomeActive:(NSNotification *)aNotification { - [self readPasteboard]; +- (void)applicationWillBecomeActive:(NSNotification *)aNotification +{ + if (quartzRootless) + [self show]; } @end @@ -420,7 +576,8 @@ static NSPortMessage *signalMessage; // Send a message to the main thread, which calls handlePortMessage in // response. Must only be called from the X server thread because // NSPort is not thread safe. -void QuartzMessageMainThread(unsigned msg) { +void QuartzMessageMainThread(unsigned msg) +{ [signalMessage setMsgid:msg]; [signalMessage sendBeforeDate:[NSDate distantPast]]; } |