merge latest (4.3.99.16) from XFree86 (vendor) branch

This commit is contained in:
Kaleb Keithley
2003-11-26 22:49:07 +00:00
parent c57959ad6a
commit 0097b6fe2d
796 changed files with 58012 additions and 26524 deletions

View File

@@ -34,7 +34,7 @@
* sale, use or other dealings in this Software without prior written
* authorization.
*/
/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/XServer.m,v 1.8 2003/01/23 00:34:26 torrey Exp $ */
/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/XServer.m,v 1.17 2003/11/14 20:27:58 torrey Exp $ */
#include "quartzCommon.h"
@@ -42,7 +42,12 @@
#include "X.h"
#include "Xproto.h"
#include "os.h"
#include "opaque.h"
#include "darwin.h"
#include "quartz.h"
#define _APPLEWM_SERVER_
#include "applewm.h"
#include "applewmExt.h"
#undef BOOL
#import "XServer.h"
@@ -64,14 +69,6 @@
#import <IOKit/pwr_mgt/IOPMLib.h>
#import <IOKit/IOMessage.h>
#define ENQUEUE(xe) \
{ \
char byte = 0; \
DarwinEQEnqueue(xe); \
/* signal there is an event ready to handle */ \
write(eventWriteFD, &byte, 1); \
}
// Types of shells
enum {
shell_Unknown,
@@ -90,7 +87,7 @@ static shellList_t const shellList[] = {
{ "sh", shell_Bourne }, // standard Bourne shell
{ "zsh", shell_Bourne }, // Z shell
{ "bash", shell_Bourne }, // GNU Bourne again shell
{ NULL, shell_Unknown }
{ NULL, shell_Unknown }
};
extern int argcGlobal;
@@ -99,7 +96,6 @@ extern char **envpGlobal;
extern int main(int argc, char *argv[], char *envp[]);
extern void HideMenuBar(void);
extern void ShowMenuBar(void);
extern void QuartzReallySetCursor();
static void childDone(int sig);
static void powerDidChange(void *x, io_service_t y, natural_t messageType,
void *messageArgument);
@@ -122,15 +118,15 @@ static io_connect_t root_port;
serverState = server_NotStarted;
serverLock = [[NSRecursiveLock alloc] init];
pendingClients = nil;
clientPID = 0;
sendServerEvents = NO;
x11Active = YES;
serverVisible = NO;
rootlessMenuBarVisible = YES;
queueShowServer = YES;
quartzServerQuitting = NO;
mouseState = 0;
eventWriteFD = quartzEventWriteFD;
windowClass = [NSWindow class];
// set up a port to safely send messages to main thread from server thread
signalPort = [[NSPort port] retain];
@@ -145,6 +141,11 @@ static io_connect_t root_port;
[[NSRunLoop currentRunLoop] addPort:signalPort
forMode:NSModalPanelRunLoopMode];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(windowBecameKey:)
name:NSWindowDidBecomeKeyNotification
object:nil];
return self;
}
@@ -164,7 +165,7 @@ static io_connect_t root_port;
[self showServer:NO];
sendServerEvents = NO;
if (clientPID != 0 || !quartzStartClients) {
if (!quitWithoutQuery && (clientPID != 0 || !quartzStartClients)) {
int but;
but = NSRunAlertPanel(NSLocalizedString(@"Quit X server?",@""),
@@ -270,11 +271,18 @@ static io_connect_t root_port;
break;
case NSLeftMouseDown:
[self getMousePosition:&xe fromEvent:anEvent];
if (quartzRootless &&
! ([anEvent window] &&
[[anEvent window] isKindOfClass:windowClass])) {
// Click in non X window - ignore
return NO;
if (quartzRootless) {
// Check that event is in X11 window
if (!quartzProcs->IsX11Window([anEvent window],
[anEvent windowNumber]))
{
if (x11Active)
[self activateX11:NO];
return NO;
} else {
if (!x11Active)
[self activateX11:YES];
}
}
mouse1Pressed = YES;
xe.u.u.type = ButtonPress;
@@ -310,6 +318,8 @@ static io_connect_t root_port;
break;
case NSKeyDown:
case NSKeyUp:
if (!x11Active)
return NO;
// If the mouse is not on the valid X display area,
// we don't send the X server key events.
if (![self getMousePosition:&xe fromEvent:nil])
@@ -321,6 +331,8 @@ static io_connect_t root_port;
xe.u.u.detail = [anEvent keyCode];
break;
case NSFlagsChanged:
if (!x11Active)
return NO;
[self getMousePosition:&xe fromEvent:nil];
xe.u.u.type = kXDarwinUpdateModifiers;
xe.u.clientMessage.u.l.longs0 = flags;
@@ -335,14 +347,13 @@ static io_connect_t root_port;
[self sendXEvent:&xe];
// Rootless: Send first NSLeftMouseDown to windows and views so window
// ordering can be suppressed.
// Rootless: Send first NSLeftMouseDown to Cocoa 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 &&
(type == NSLeftMouseDown || type == NSLeftMouseUp) &&
[anEvent clickCount] == 1 &&
[[anEvent window] isKindOfClass:windowClass])
[anEvent clickCount] == 1 && [anEvent window])
{
return NO;
}
@@ -429,6 +440,27 @@ static io_connect_t root_port;
}
}
// Load the appropriate display mode bundle
- (BOOL)loadDisplayBundle
{
if (quartzRootless) {
NSEnumerator *enumerator = [[Preferences displayModeBundles]
objectEnumerator];
NSString *bundleName;
while ((bundleName = [enumerator nextObject])) {
if (QuartzLoadDisplayBundle([bundleName cString]))
return YES;
}
return NO;
} else {
return QuartzLoadDisplayBundle("fullscreen.bundle");
}
}
// Start the X server thread and the client process
- (void)startX
{
@@ -455,6 +487,9 @@ static io_connect_t root_port;
else
NSLog(@"No version");
if (![self loadDisplayBundle])
[NSApp terminate:nil];
// Start the X server thread
serverState = server_Starting;
[NSThread detachNewThreadSelector:@selector(run) toTarget:self
@@ -517,6 +552,19 @@ static io_connect_t root_port;
if (quartzServerQuitting) {
[self quitServer];
[NSApp replyToApplicationShouldTerminate:YES];
return;
}
if (pendingClients) {
NSEnumerator *enumerator = [pendingClients objectEnumerator];
NSString *filename;
while ((filename = [enumerator nextObject])) {
[self runClient:filename];
}
[pendingClients release];
pendingClients = nil;
}
}
@@ -666,6 +714,87 @@ static io_connect_t root_port;
return YES;
}
// Start the specified client in its own task
// FIXME: This should be unified with startXClients
- (void)runClient:(NSString *)filename
{
const char *command = [filename UTF8String];
const char *shell;
const char *argv[5];
int child1, child2 = 0;
int status;
shell = getenv("SHELL");
if (shell == NULL)
shell = "/bin/bash";
/* At least [ba]sh, [t]csh and zsh all work with this syntax. We
need to use an interactive shell to force it to load the user's
environment. */
argv[0] = shell;
argv[1] = "-i";
argv[2] = "-c";
argv[3] = command;
argv[4] = NULL;
/* Do the fork-twice trick to avoid having to reap zombies */
child1 = fork();
switch (child1) {
case -1: /* error */
break;
case 0: /* child1 */
child2 = fork();
switch (child2) {
int max_files, i;
char buf[1024], *tem;
case -1: /* error */
_exit(1);
case 0: /* child2 */
/* close all open files except for standard streams */
max_files = sysconf(_SC_OPEN_MAX);
for (i = 3; i < max_files; i++)
close(i);
/* ensure stdin is on /dev/null */
close(0);
open("/dev/null", O_RDONLY);
/* cd $HOME */
tem = getenv("HOME");
if (tem != NULL)
chdir(tem);
/* Setup environment */
snprintf(buf, sizeof(buf), ":%s", display);
setenv("DISPLAY", buf, TRUE);
tem = getenv("PATH");
if (tem != NULL && tem[0] != NULL)
snprintf(buf, sizeof(buf), "%s:/usr/X11R6/bin", tem);
else
snprintf(buf, sizeof(buf), "/bin:/usr/bin:/usr/X11R6/bin");
setenv("PATH", buf, TRUE);
execvp(argv[0], (char **const) argv);
_exit(2);
default: /* parent (child1) */
_exit(0);
}
break;
default: /* parent */
waitpid(child1, &status, 0);
}
}
// Run the X server thread
- (void)run
{
@@ -712,6 +841,12 @@ static io_connect_t root_port;
[NSApp activateIgnoringOtherApps:YES];
}
// Show the Aqua-X11 switch panel useful for fullscreen mode
- (IBAction)showSwitchPanel:(id)sender
{
[switchWindow orderFront:nil];
}
// Show the X server when sent message from GUI
- (IBAction)showAction:(id)sender
{
@@ -787,11 +922,10 @@ static io_connect_t root_port;
if (show) {
if (!quartzRootless) {
QuartzFSCapture();
quartzProcs->CaptureScreens();
HideMenuBar();
}
xe.u.u.type = kXDarwinShow;
[self sendXEvent:&xe];
[self activateX11:YES];
// the mouse location will have moved; track it
xe.u.u.type = MotionNotify;
@@ -802,14 +936,19 @@ static io_connect_t root_port;
xe.u.clientMessage.u.l.longs0 = [[NSApp currentEvent] modifierFlags];
[self sendXEvent:&xe];
// put the pasteboard into the X cut buffer
[self readPasteboard];
// If there is no AppleWM-aware cut and paste manager, do what we can.
if ((AppleWMSelectedEvents() & AppleWMPasteboardNotifyMask) == 0) {
// put the pasteboard into the X cut buffer
[self readPasteboard];
}
} else {
// put the X cut buffer on the pasteboard
[self writePasteboard];
// If there is no AppleWM-aware cut and paste manager, do what we can.
if ((AppleWMSelectedEvents() & AppleWMPasteboardNotifyMask) == 0) {
// put the X cut buffer on the pasteboard
[self writePasteboard];
}
xe.u.u.type = kXDarwinHide;
[self sendXEvent:&xe];
[self activateX11:NO];
}
serverVisible = show;
@@ -877,7 +1016,7 @@ static io_connect_t root_port;
}
#endif
ENQUEUE(xe);
DarwinEQEnqueue(xe);
}
// Handle messages from the X server thread
@@ -885,12 +1024,12 @@ static io_connect_t root_port;
{
unsigned msg = [portMessage msgid];
switch(msg) {
switch (msg) {
case kQuartzServerHidden:
// Make sure the X server wasn't queued to be shown again while
// the hide was pending.
if (!quartzRootless && !serverVisible) {
QuartzFSRelease();
quartzProcs->ReleaseScreens();
ShowMenuBar();
}
break;
@@ -908,13 +1047,43 @@ static io_connect_t root_port;
break;
case kQuartzCursorUpdate:
QuartzReallySetCursor();
if (quartzProcs->CursorUpdate)
quartzProcs->CursorUpdate();
break;
case kQuartzPostEvent:
{
const xEvent *xe = [[[portMessage components] lastObject] bytes];
ENQUEUE(xe);
DarwinEQEnqueue(xe);
break;
}
case kQuartzSetWindowMenu:
{
NSArray *list;
[[[portMessage components] lastObject] getBytes:&list];
[self setX11WindowList:list];
[list release];
break;
}
case kQuartzSetWindowMenuCheck:
{
int n;
[[[portMessage components] lastObject] getBytes:&n];
[self setX11WindowCheck:[NSNumber numberWithInt:n]];
break;
}
case kQuartzSetFrontProcess:
[NSApp activateIgnoringOtherApps:YES];
break;
case kQuartzSetCanQuit:
{
int n;
[[[portMessage components] lastObject] getBytes:&n];
quitWithoutQuery = (BOOL) n;
break;
}
@@ -939,6 +1108,234 @@ static io_connect_t root_port;
}
}
// User selected an X11 window from a menu
- (IBAction)itemSelected:(id)sender
{
xEvent xe;
[NSApp activateIgnoringOtherApps:YES];
// Notify the client of the change through the X server thread
xe.u.u.type = kXDarwinControllerNotify;
xe.u.clientMessage.u.l.longs0 = AppleWMWindowMenuItem;
xe.u.clientMessage.u.l.longs1 = [sender tag];
[self sendXEvent:&xe];
}
// User selected Next from window menu
- (IBAction)nextWindow:(id)sender
{
QuartzMessageServerThread(kXDarwinControllerNotify, 1,
AppleWMNextWindow);
}
// User selected Previous from window menu
- (IBAction)previousWindow:(id)sender
{
QuartzMessageServerThread(kXDarwinControllerNotify, 1,
AppleWMPreviousWindow);
}
/*
* The XPR implementation handles close, minimize, and zoom actions for X11
* windows here, while CR handles these in the NSWindow class.
*/
// Handle Close from window menu for X11 window in XPR implementation
- (IBAction)performClose:(id)sender
{
QuartzMessageServerThread(kXDarwinControllerNotify, 1,
AppleWMCloseWindow);
}
// Handle Minimize from window menu for X11 window in XPR implementation
- (IBAction)performMiniaturize:(id)sender
{
QuartzMessageServerThread(kXDarwinControllerNotify, 1,
AppleWMMinimizeWindow);
}
// Handle Zoom from window menu for X11 window in XPR implementation
- (IBAction)performZoom:(id)sender
{
QuartzMessageServerThread(kXDarwinControllerNotify, 1,
AppleWMZoomWindow);
}
// Handle "Bring All to Front" from window menu
- (IBAction)bringAllToFront:(id)sender
{
if ((AppleWMSelectedEvents() & AppleWMControllerNotifyMask) != 0) {
QuartzMessageServerThread(kXDarwinControllerNotify, 1,
AppleWMBringAllToFront);
} else {
[NSApp arrangeInFront:nil];
}
}
// This ends up at the end of the responder chain.
- (IBAction)copy:(id)sender
{
QuartzMessageServerThread(kXDarwinPasteboardNotify, 1,
AppleWMCopyToPasteboard);
}
// Set whether or not X11 is active and should receive all key events
- (void)activateX11:(BOOL)state
{
if (state) {
QuartzMessageServerThread(kXDarwinActivate, 0);
}
else {
QuartzMessageServerThread(kXDarwinDeactivate, 0);
}
x11Active = state;
}
// Some NSWindow became the key window
- (void)windowBecameKey:(NSWindow *)window
{
if (quartzProcs->IsX11Window(window, [window windowNumber])) {
if (!x11Active)
[self activateX11:YES];
} else {
if (x11Active)
[self activateX11:NO];
}
}
// Set the Apple-WM specifiable part of the window menu
- (void)setX11WindowList:(NSArray *)list
{
NSMenuItem *item;
int first, count, i;
xEvent xe;
/* Work backwards so we don't mess up the indices */
first = [windowMenu indexOfItem:windowSeparator] + 1;
if (first > 0) {
count = [windowMenu numberOfItems];
for (i = count - 1; i >= first; i--)
[windowMenu removeItemAtIndex:i];
} else {
windowSeparator = (NSMenuItem *)[windowMenu addItemWithTitle:@""
action:nil
keyEquivalent:@""];
}
count = [dockMenu numberOfItems];
for (i = 0; i < count; i++)
[dockMenu removeItemAtIndex:0];
count = [list count];
for (i = 0; i < count; i++)
{
NSString *name, *shortcut;
name = [[list objectAtIndex:i] objectAtIndex:0];
shortcut = [[list objectAtIndex:i] objectAtIndex:1];
item = (NSMenuItem *)[windowMenu addItemWithTitle:name
action:@selector(itemSelected:)
keyEquivalent:shortcut];
[item setTarget:self];
[item setTag:i];
[item setEnabled:YES];
item = (NSMenuItem *)[dockMenu insertItemWithTitle:name
action:@selector(itemSelected:)
keyEquivalent:shortcut atIndex:i];
[item setTarget:self];
[item setTag:i];
[item setEnabled:YES];
}
if (checkedWindowItem >= 0 && checkedWindowItem < count)
{
item = (NSMenuItem *)[windowMenu itemAtIndex:first + checkedWindowItem];
[item setState:NSOnState];
item = (NSMenuItem *)[dockMenu itemAtIndex:checkedWindowItem];
[item setState:NSOnState];
}
// Notify the client of the change through the X server thread
xe.u.u.type = kXDarwinControllerNotify;
xe.u.clientMessage.u.l.longs0 = AppleWMWindowMenuNotify;
[self sendXEvent:&xe];
}
// Set the checked item on the Apple-WM specifiable window menu
- (void)setX11WindowCheck:(NSNumber *)nn
{
NSMenuItem *item;
int first, count;
int n = [nn intValue];
first = [windowMenu indexOfItem:windowSeparator] + 1;
count = [windowMenu numberOfItems] - first;
if (checkedWindowItem >= 0 && checkedWindowItem < count)
{
item = (NSMenuItem *)[windowMenu itemAtIndex:first + checkedWindowItem];
[item setState:NSOffState];
item = (NSMenuItem *)[dockMenu itemAtIndex:checkedWindowItem];
[item setState:NSOffState];
}
if (n >= 0 && n < count)
{
item = (NSMenuItem *)[windowMenu itemAtIndex:first + n];
[item setState:NSOnState];
item = (NSMenuItem *)[dockMenu itemAtIndex:n];
[item setState:NSOnState];
}
checkedWindowItem = n;
}
// Return whether or not a menu item should be enabled
- (BOOL)validateMenuItem:(NSMenuItem *)item
{
NSMenu *menu = [item menu];
if (menu == windowMenu && [item tag] == 30) {
// Mode switch panel is for fullscreen only
return !quartzRootless;
}
else if ((menu == windowMenu && [item tag] != 40) || menu == dockMenu) {
// The special window and dock menu items should not be active unless
// there is an AppleWM-aware window manager running.
return (AppleWMSelectedEvents() & AppleWMControllerNotifyMask) != 0;
}
else {
return TRUE;
}
}
/*
* Application Delegate Methods
*/
- (void)applicationDidHide:(NSNotification *)aNotification
{
if ((AppleWMSelectedEvents() & AppleWMControllerNotifyMask) != 0) {
QuartzMessageServerThread(kXDarwinControllerNotify, 1,
AppleWMHideAll);
} else {
// FIXME: We need to hide Xplugin windows here
}
}
- (void)applicationDidUnhide:(NSNotification *)aNotification
{
if ((AppleWMSelectedEvents() & AppleWMControllerNotifyMask) != 0) {
QuartzMessageServerThread(kXDarwinControllerNotify, 1,
AppleWMShowAll);
} else {
[NSApp arrangeInFront:nil];
}
}
// Called when the user clicks the application icon,
// but not when Cmd-Tab is used.
// Rootless: Don't switch until applicationWillBecomeActive.
@@ -958,8 +1355,38 @@ static io_connect_t root_port;
- (void)applicationWillBecomeActive:(NSNotification *)aNotification
{
if (quartzRootless)
if (quartzRootless) {
[self showServer:YES];
// If there is no AppleWM-aware window manager, we can't allow
// interleaving of Aqua and X11 windows.
if ((AppleWMSelectedEvents() & AppleWMControllerNotifyMask) == 0) {
[NSApp arrangeInFront:nil];
}
}
}
// Called when the user opens a document type that we claim (ie. an X11 executable).
- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
{
if (serverState == server_Running) {
[self runClient:filename];
return YES;
}
else if (serverState == server_NotStarted || serverState == server_Starting) {
if ([filename UTF8String][0] != ':') { // Ignore display names
if (!pendingClients) {
pendingClients = [[NSMutableArray alloc] initWithCapacity:1];
}
[pendingClients addObject:filename];
return YES; // Assume it will launch successfully
}
return NO;
}
// If the server is quitting or done,
// its too late to launch new clients this time.
return NO;
}
@end
@@ -970,7 +1397,7 @@ static io_connect_t root_port;
// NSPort is not thread safe.
void QuartzMessageMainThread(unsigned msg, void *data, unsigned length)
{
if (msg == kQuartzPostEvent) {
if (length > 0) {
NSData *eventData = [NSData dataWithBytes:data length:length];
NSArray *eventArray = [NSArray arrayWithObject:eventData];
NSPortMessage *newMessage =
@@ -986,6 +1413,36 @@ void QuartzMessageMainThread(unsigned msg, void *data, unsigned length)
}
}
void
QuartzSetWindowMenu(int nitems, const char **items,
const char *shortcuts)
{
NSMutableArray *array;
int i;
array = [[NSMutableArray alloc] initWithCapacity:nitems];
for (i = 0; i < nitems; i++) {
NSMutableArray *subarray = [NSMutableArray arrayWithCapacity:2];
NSString *string = [NSString stringWithUTF8String:items[i]];
[subarray addObject:string];
if (shortcuts[i] != 0) {
NSString *number = [NSString stringWithFormat:@"%d",
shortcuts[i]];
[subarray addObject:number];
} else
[subarray addObject:@""];
[array addObject:subarray];
}
/* Send the array of strings over to the main thread. */
/* Will be released in main thread. */
QuartzMessageMainThread(kQuartzSetWindowMenu, &array, sizeof(NSArray *));
}
// Handle SIGCHLD signals
static void childDone(int sig)
{
@@ -1025,5 +1482,5 @@ static void powerDidChange(
}
break;
}
}