2023-08-01 15:58:11 +00:00
|
|
|
/* -*- mode:ObjC -*-
|
2023-08-08 11:35:26 +00:00
|
|
|
HeadlessServer - X11 Server Class
|
2023-08-01 15:58:11 +00:00
|
|
|
|
2023-08-17 10:47:55 +00:00
|
|
|
Copyright (C) 1998,2002,2023 Free Software Foundation, Inc.
|
2023-08-01 15:58:11 +00:00
|
|
|
|
2023-08-17 10:47:55 +00:00
|
|
|
Re-written by: Gregory John Casamento <greg.casamento@gmail.com>
|
|
|
|
Based on work by: Marcian Lytwyn <gnustep@advcsi.com> for Keysight
|
|
|
|
Based on work Written by: Adam Fedor <fedor@gnu.org>
|
|
|
|
Date: Mar 2002, Aug 2023
|
2023-08-01 15:58:11 +00:00
|
|
|
|
|
|
|
This file is part of the GNU Objective C User Interface Library.
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Lesser General Public
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Lesser General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
|
|
License along with this library; see the file COPYING.LIB.
|
|
|
|
If not, see <http://www.gnu.org/licenses/> or write to the
|
|
|
|
Free Software Foundation, 51 Franklin Street, Fifth Floor,
|
|
|
|
Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
#include <AppKit/AppKitExceptions.h>
|
|
|
|
#include <AppKit/NSApplication.h>
|
|
|
|
#include <AppKit/NSView.h>
|
|
|
|
#include <AppKit/NSWindow.h>
|
|
|
|
#include <Foundation/NSException.h>
|
|
|
|
#include <Foundation/NSArray.h>
|
|
|
|
#include <Foundation/NSConnection.h>
|
|
|
|
#include <Foundation/NSDictionary.h>
|
|
|
|
#include <Foundation/NSData.h>
|
|
|
|
#include <Foundation/NSRunLoop.h>
|
|
|
|
#include <Foundation/NSValue.h>
|
|
|
|
#include <Foundation/NSString.h>
|
|
|
|
#include <Foundation/NSUserDefaults.h>
|
|
|
|
#include <Foundation/NSDebug.h>
|
|
|
|
|
|
|
|
#include <signal.h>
|
|
|
|
/* Terminate cleanly if we get a signal to do so */
|
|
|
|
static void
|
|
|
|
terminate(int sig)
|
|
|
|
{
|
|
|
|
if (nil != NSApp)
|
|
|
|
{
|
|
|
|
[NSApp terminate: NSApp];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-08 11:35:26 +00:00
|
|
|
#include "xheadless/HeadlessServer.h"
|
|
|
|
#include "xheadless/HeadlessInputServer.h"
|
2023-08-01 15:58:11 +00:00
|
|
|
|
|
|
|
extern int XGErrorHandler(Display *display, XErrorEvent *err);
|
|
|
|
|
2023-08-08 11:35:26 +00:00
|
|
|
@interface HeadlessServer (Window)
|
2023-08-01 15:58:11 +00:00
|
|
|
- (void) _setupRootWindow;
|
|
|
|
@end
|
|
|
|
|
2023-08-08 11:35:26 +00:00
|
|
|
@interface HeadlessServer (Private)
|
2023-08-01 15:58:11 +00:00
|
|
|
- (void) setupRunLoopInputSourcesForMode: (NSString*)mode;
|
|
|
|
@end
|
|
|
|
|
2023-08-08 11:35:26 +00:00
|
|
|
@interface HeadlessScreenContext : NSObject
|
2023-08-01 15:58:11 +00:00
|
|
|
{
|
|
|
|
RContext *rcontext;
|
|
|
|
XGDrawMechanism drawMechanism;
|
|
|
|
}
|
|
|
|
|
2023-08-02 13:22:08 +00:00
|
|
|
- (instancetype) initForDisplay: (Display *)dpy screen: (int)screen_number;
|
2023-08-01 15:58:11 +00:00
|
|
|
- (XGDrawMechanism) drawMechanism;
|
|
|
|
- (RContext *) context;
|
|
|
|
@end
|
|
|
|
|
2023-08-08 11:35:26 +00:00
|
|
|
@implementation HeadlessScreenContext
|
2023-08-01 15:58:11 +00:00
|
|
|
|
|
|
|
- (RContextAttributes *) _getXDefaults
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
- initForDisplay: (Display *)dpy screen: (int)screen_number
|
|
|
|
{
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) dealloc
|
|
|
|
{
|
|
|
|
[super dealloc];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (XGDrawMechanism) drawMechanism
|
|
|
|
{
|
|
|
|
return drawMechanism;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (RContext *) context
|
|
|
|
{
|
|
|
|
return rcontext;
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
<unit>
|
2023-08-08 11:35:26 +00:00
|
|
|
<heading>HeadlessServer</heading>
|
2023-08-01 15:58:11 +00:00
|
|
|
|
2023-08-08 11:35:26 +00:00
|
|
|
<p> HeadlessServer is a concrete subclass of GSDisplayServer that handles
|
2023-09-02 16:59:15 +00:00
|
|
|
events and interactions for the headless server. The purpose of the headless
|
|
|
|
server is to allow apps which would normally have an interface under X to
|
|
|
|
show no visible windows. This is useful for testing or for running applications
|
|
|
|
on machines that have no display available, but where the application needs to run.
|
|
|
|
This also can be used in continuous integration to test an application in the
|
|
|
|
background.
|
2023-08-01 15:58:11 +00:00
|
|
|
</unit>
|
|
|
|
*/
|
2023-08-08 14:22:17 +00:00
|
|
|
|
2023-08-08 11:35:26 +00:00
|
|
|
@implementation HeadlessServer
|
2023-08-01 15:58:11 +00:00
|
|
|
|
|
|
|
/* Initialize AppKit backend */
|
|
|
|
+ (void) initializeBackend
|
|
|
|
{
|
|
|
|
NSDebugLog(@"Initializing GNUstep x11 backend.\n");
|
2023-08-08 11:35:26 +00:00
|
|
|
[GSDisplayServer setDefaultServerClass: [HeadlessServer class]];
|
2023-08-01 15:58:11 +00:00
|
|
|
signal(SIGTERM, terminate);
|
|
|
|
signal(SIGINT, terminate);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Returns a pointer to the current X-Windows display variable for
|
|
|
|
the current context.
|
|
|
|
*/
|
|
|
|
+ (Display*) currentXDisplay
|
|
|
|
{
|
2023-08-08 11:35:26 +00:00
|
|
|
return [(HeadlessServer*)GSCurrentServer() xDisplay];
|
2023-08-01 15:58:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (id) _initXContext
|
|
|
|
{
|
|
|
|
int screen_number = 0, display_number = 0;
|
|
|
|
NSString *display_name;
|
|
|
|
|
|
|
|
display_name = [server_info objectForKey: GSDisplayName];
|
|
|
|
if (display_name == nil)
|
|
|
|
{
|
|
|
|
NSString *host = [[NSUserDefaults standardUserDefaults]
|
|
|
|
stringForKey: @"NSHost"];
|
|
|
|
NSString *dn = [server_info objectForKey: GSDisplayNumber];
|
|
|
|
NSString *sn = [server_info objectForKey: GSScreenNumber];
|
|
|
|
|
|
|
|
if (dn || sn)
|
|
|
|
{
|
|
|
|
if (dn == NULL)
|
|
|
|
dn = @"0";
|
|
|
|
if (sn == NULL)
|
|
|
|
sn = @"0";
|
|
|
|
if (host == nil)
|
|
|
|
host = @"";
|
|
|
|
display_name = [NSString stringWithFormat: @"%@:%@.%@", host, dn,sn];
|
|
|
|
}
|
|
|
|
else if ((host != nil) && ([host isEqual: @""] == NO))
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* If the NSHost default told us to display somewhere, we need
|
|
|
|
* to generate a display name for X from the host name and the
|
|
|
|
* default display and screen numbers (zero).
|
|
|
|
*/
|
|
|
|
display_name = [NSString stringWithFormat: @"%@:0.0", host];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
dpy = malloc(sizeof(Display)); //XOpenDisplay(NULL);
|
|
|
|
|
|
|
|
[server_info setObject: display_name forKey: GSDisplayName];
|
|
|
|
[server_info setObject: [NSNumber numberWithInt: display_number]
|
|
|
|
forKey: GSDisplayNumber];
|
|
|
|
[server_info setObject: [NSNumber numberWithInt: screen_number]
|
|
|
|
forKey: GSScreenNumber];
|
|
|
|
|
|
|
|
/* Setup screen*/
|
|
|
|
if (screenList == NULL)
|
|
|
|
screenList = NSCreateMapTable(NSIntMapKeyCallBacks,
|
|
|
|
NSObjectMapValueCallBacks, 20);
|
|
|
|
|
|
|
|
defScreen = screen_number;
|
|
|
|
|
|
|
|
[self _setupRootWindow];
|
|
|
|
inputServer = nil;
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Opens the X display (using a helper method) and sets up basic
|
|
|
|
display mechanisms, such as visuals and colormaps.
|
|
|
|
*/
|
|
|
|
- (id) initWithAttributes: (NSDictionary *)info
|
|
|
|
{
|
|
|
|
[super initWithAttributes: info];
|
|
|
|
[self _initXContext];
|
|
|
|
|
|
|
|
[self setupRunLoopInputSourcesForMode: NSDefaultRunLoopMode];
|
|
|
|
[self setupRunLoopInputSourcesForMode: NSConnectionReplyMode];
|
|
|
|
[self setupRunLoopInputSourcesForMode: NSModalPanelRunLoopMode];
|
|
|
|
[self setupRunLoopInputSourcesForMode: NSEventTrackingRunLoopMode];
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Closes all X resources, the X display and dealloc other ivars.
|
|
|
|
*/
|
|
|
|
- (void) dealloc
|
|
|
|
{
|
|
|
|
NSDebugLog(@"Destroying X11 Server");
|
|
|
|
DESTROY(inputServer);
|
|
|
|
[self _destroyServerWindows];
|
|
|
|
NSFreeMapTable(screenList);
|
|
|
|
//XCloseDisplay(dpy);
|
|
|
|
free(dpy);
|
|
|
|
[super dealloc];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Returns a pointer to the X windows display variable
|
|
|
|
*/
|
|
|
|
- (Display *) xDisplay
|
|
|
|
{
|
|
|
|
return dpy;
|
|
|
|
}
|
|
|
|
|
2023-08-08 11:35:26 +00:00
|
|
|
- (HeadlessScreenContext *) _screenContextForScreen: (int)screen_number
|
2023-08-01 15:58:11 +00:00
|
|
|
{
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Returns a pointer to a structure which describes aspects of the
|
|
|
|
X windows display
|
|
|
|
*/
|
|
|
|
- (void *) xrContextForScreen: (int)screen_number
|
|
|
|
{
|
|
|
|
return [[self _screenContextForScreen: screen_number] context];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (Visual *) visualForScreen: (int)screen_number
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (int) depthForScreen: (int)screen_number
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Returns the XGDrawMechanism, which roughly describes the depth of
|
|
|
|
the screen and how pixels should be drawn to the screen for maximum
|
|
|
|
speed.
|
|
|
|
*/
|
|
|
|
- (XGDrawMechanism) drawMechanismForScreen: (int)screen_number
|
|
|
|
{
|
|
|
|
return [[self _screenContextForScreen: screen_number] drawMechanism];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Used by the art backend to determine the drawing mechanism.
|
|
|
|
*/
|
|
|
|
- (void) getForScreen: (int)screen_number pixelFormat: (int *)bpp_number
|
|
|
|
masks: (int *)red_mask : (int *)green_mask : (int *)blue_mask
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Returns the root window of the display
|
|
|
|
*/
|
|
|
|
- (Window) xDisplayRootWindowForScreen: (int)screen_number;
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Returns the closest color in the current colormap to the indicated
|
|
|
|
X color
|
|
|
|
*/
|
|
|
|
- (XColor) xColorFromColor: (XColor)color forScreen: (int)screen_number
|
|
|
|
{
|
|
|
|
return color;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Returns the application root window, which is used for many things
|
|
|
|
such as window hints
|
|
|
|
*/
|
|
|
|
- (Window) xAppRootWindow
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
Wait for all contexts to finish processing. Only used with XDPS graphics.
|
|
|
|
*/
|
|
|
|
+ (void) waitAllContexts
|
|
|
|
{
|
|
|
|
if ([[GSCurrentContext() class]
|
|
|
|
respondsToSelector: @selector(waitAllContexts)])
|
|
|
|
[[GSCurrentContext() class] waitAllContexts];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) beep
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
- glContextClass
|
|
|
|
{
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
- glPixelFormatClass
|
|
|
|
{
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
2023-08-08 11:35:26 +00:00
|
|
|
@implementation HeadlessServer (InputMethod)
|
2023-08-01 15:58:11 +00:00
|
|
|
- (NSString *) inputMethodStyle
|
|
|
|
{
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *) fontSize: (int *)size
|
|
|
|
{
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL) clientWindowRect: (NSRect *)rect
|
|
|
|
{
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL) statusArea: (NSRect *)rect
|
|
|
|
{
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL) preeditArea: (NSRect *)rect
|
|
|
|
{
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL) preeditSpot: (NSPoint *)p
|
|
|
|
{
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL) setStatusArea: (NSRect *)rect
|
|
|
|
{
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL) setPreeditArea: (NSRect *)rect
|
|
|
|
{
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL) setPreeditSpot: (NSPoint *)p
|
|
|
|
{
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
@end // XGServer (InputMethod)
|
|
|
|
|
|
|
|
//==== End: Additional Code for NSTextView ====================================
|