libs-back/Source/xheadless/HeadlessServerWindow.m
Gregory Casamento 20d678fe9f -am
2023-09-02 16:59:15 +00:00

759 lines
16 KiB
Objective-C

/* XGServerWindows - methods for window/screen handling
Copyright (C) 1998,2002,2023 Free Software Foundation, Inc.
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: Nov 1999, Aug 2023
This file is part of GNUstep
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 <math.h>
#include <Foundation/NSString.h>
#include <Foundation/NSArray.h>
#include <Foundation/NSDebug.h>
#include <Foundation/NSValue.h>
#include <Foundation/NSProcessInfo.h>
#include <Foundation/NSUserDefaults.h>
#include <Foundation/NSAutoreleasePool.h>
#include <Foundation/NSDebug.h>
#include <AppKit/NSEvent.h>
#include <Foundation/NSException.h>
#include <Foundation/NSThread.h>
#include <AppKit/DPSOperators.h>
#include <AppKit/NSApplication.h>
#include <AppKit/NSCursor.h>
#include <AppKit/NSGraphics.h>
#include <AppKit/NSWindow.h>
#include <AppKit/NSImage.h>
#include <AppKit/NSBitmapImageRep.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <xheadless/HeadlessServerWindow.h>
#include <xheadless/HeadlessGeneric.h>
#include <xheadless/XWindowBuffer.h>
#include <xheadless/HeadlessServer.h>
#define ROOT generic.appRootWindow
static BOOL handlesWindowDecorations = YES;
#define WINDOW_WITH_TAG(windowNumber) (gswindow_device_t *)NSMapGet(windowtags, (void *)(uintptr_t)windowNumber)
/* Keep track of windows */
static NSMapTable *windowmaps = NULL;
static NSMapTable *windowtags = NULL;
/* Track used window numbers */
static int last_win_num = 0;
@interface NSCursor (BackendPrivate)
- (void *)_cid;
@end
@interface NSBitmapImageRep (GSPrivate)
- (NSBitmapImageRep *) _convertToFormatBitsPerSample: (NSInteger)bps
samplesPerPixel: (NSInteger)spp
hasAlpha: (BOOL)alpha
isPlanar: (BOOL)isPlanar
colorSpaceName: (NSString*)colorSpaceName
bitmapFormat: (NSBitmapFormat)bitmapFormat
bytesPerRow: (NSInteger)rowBytes
bitsPerPixel: (NSInteger)pixelBits;
@end
void __objc_xgcontextwindow_linking (void)
{
}
@interface NSEvent (WindowHack)
- (void) _patchLocation: (NSPoint)loc;
@end
@implementation NSEvent (WindowHack)
- (void) _patchLocation: (NSPoint)loc
{
location_point = loc;
}
@end
@interface HeadlessServer (WindowOps)
- (gswindow_device_t *) _rootWindowForScreen: (int)screen;
- (void) styleoffsets: (float *) l : (float *) r : (float *) t : (float *) b
: (unsigned int) style : (Window) win;
- (void) _setSupportedWMProtocols: (gswindow_device_t *) window;
@end
@implementation HeadlessServer (WindowOps)
- (BOOL) handlesWindowDecorations
{
return handlesWindowDecorations;
}
/*
* Where a window has been reparented by the wm, we use this method to
* locate the window given knowledge of its border window.
*/
+ (gswindow_device_t *) _windowForXParent: (Window)xWindow
{
NSMapEnumerator enumerator;
void *key;
gswindow_device_t *d;
enumerator = NSEnumerateMapTable(windowmaps);
while (NSNextMapEnumeratorPair(&enumerator, &key, (void**)&d) == YES)
{
if (d->root != d->parent && d->parent == xWindow)
{
return d;
}
}
return 0;
}
+ (gswindow_device_t *) _windowForXWindow: (Window)xWindow
{
return NSMapGet(windowmaps, (void *)xWindow);
}
+ (gswindow_device_t *) _windowWithTag: (int)windowNumber
{
return WINDOW_WITH_TAG(windowNumber);
}
/*
* Convert a window frame in OpenStep absolute screen coordinates to
* a frame in X absolute screen coordinates by flipping an applying
* offsets to allow for the X window decorations.
* The result is the rectangle of the window we can actually draw
* to (in the X coordinate system).
*/
- (NSRect) _OSFrameToXFrame: (NSRect)o for: (void*)window
{
return NSMakeRect(0, 0, 0, 0);
}
/*
* Convert a window frame in OpenStep absolute screen coordinates to
* a frame suitable for setting X hints for a window manager.
* NB. Hints use the coordinates of the parent decoration window,
* but the size of the actual window.
*/
- (NSRect) _OSFrameToXHints: (NSRect)o for: (void*)window
{
return NSMakeRect(0, 0, 0, 0);
}
/*
* Convert a rectangle in X coordinates relative to the X-window
* to a rectangle in OpenStep coordinates (base coordinates of the NSWindow).
*/
- (NSRect) _XWinRectToOSWinRect: (NSRect)x for: (void*)window
{
return NSMakeRect(0, 0, 0, 0);
}
/*
* Convert a window frame in X absolute screen coordinates to a frame
* in OpenStep absolute screen coordinates by flipping an applying
* offsets to allow for the X window decorations.
*/
- (NSRect) _XFrameToOSFrame: (NSRect)x for: (void*)window
{
return NSMakeRect(0, 0, 0, 0);
}
/*
* Convert a window frame in X absolute screen coordinates to
* a frame suitable for setting X hints for a window manager.
*/
- (NSRect) _XFrameToXHints: (NSRect)o for: (void*)window
{
return NSMakeRect(0, 0, 0, 0);
}
- (void)_sendRoot: (Window)root
type: (Atom)type
window: (Window)window
data0: (long)data0
data1: (long)data1
data2: (long)data2
data3: (long)data3
{
}
/*
* Check if the window manager supports a feature.
*/
- (BOOL) _checkWMSupports: (Atom)feature
{
return NO;
}
Bool _get_next_prop_new_event(Display *display, XEvent *event, char *arg)
{
return False;
}
- (BOOL) _tryRequestFrameExtents: (gswindow_device_t *)window
{
return NO;
}
- (BOOL) _checkStyle: (unsigned)style
{
NSDebugLLog(@"Offset", @"Checking offsets for style %d\n", style);
return NO;
}
- (XGWMProtocols) _checkWindowManager
{
return XGWM_UNKNOWN;
}
- (gswindow_device_t *) _rootWindowForScreen: (int)screen
{
gswindow_device_t *window;
/* Screen number is negative to avoid conflict with windows */
window = WINDOW_WITH_TAG(-screen);
if (window)
return window;
window = NSAllocateCollectable(sizeof(gswindow_device_t), NSScannedOption);
memset(window, '\0', sizeof(gswindow_device_t));
window->display = dpy;
window->screen = screen;
window->ident = 0; //RootWindow(dpy, screen);
window->root = window->ident;
window->type = NSBackingStoreNonretained;
window->number = -screen;
window->map_state = IsViewable;
window->visibility = -1;
window->wm_state = NormalState;
window->xframe = NSMakeRect(0, 0, 0, 0);
NSMapInsert (windowtags, (void*)(uintptr_t)window->number, window);
NSMapInsert (windowmaps, (void*)(uintptr_t)window->ident, window);
return window;
}
/* Create the window and screen list if necessary, add the root window to
the window list as window 0 */
- (void) _checkWindowlist
{
if (windowmaps)
return;
windowmaps = NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks,
NSNonOwnedPointerMapValueCallBacks, 20);
windowtags = NSCreateMapTable(NSIntMapKeyCallBacks,
NSNonOwnedPointerMapValueCallBacks, 20);
}
- (void) _setupMouse
{
}
- (void) _setSupportedWMProtocols: (gswindow_device_t *) window
{
}
- (void) _setupRootWindow
{
/*
* Initialize time of last events to be the start of time - not
* the current time!
*/
generic.lastClick = 1;
generic.lastMotion = 1;
generic.lastTime = 1;
/*
* Set up standard atoms.
*/
[self _checkWindowlist];
handlesWindowDecorations = NO;
return;
}
/* Destroys all the windows and other window resources that belong to
this context */
- (void) _destroyServerWindows
{
void *key;
gswindow_device_t *d;
NSMapEnumerator enumerator;
NSMapTable *mapcopy;
/* Have to get a copy, since termwindow will remove them from
the map table */
mapcopy = NSCopyMapTableWithZone(windowtags, [self zone]);
enumerator = NSEnumerateMapTable(mapcopy);
while (NSNextMapEnumeratorPair(&enumerator, &key, (void**)&d) == YES)
{
if (d->display == dpy && d->ident != d->root)
[self termwindow: (NSInteger)(intptr_t)key];
}
NSFreeMapTable(mapcopy);
}
/* Sets up a backing pixmap when a window is created or resized. This is
only done if the Window is buffered or retained. */
- (void) _createBuffer: (gswindow_device_t *)window
{
}
/*
* Code to build up a NET WM icon from our application icon
*/
-(BOOL) _createNetIcon: (NSImage*)image
result: (long**)pixeldata
size: (int*)size
{
return NO;
}
- (void) _setNetWMIconFor: (Window) window
{
}
- (int) window: (NSRect)frame
: (NSBackingStoreType)type
: (unsigned int)style
: (int)screen
{
gswindow_device_t *window;
NSDebugLLog(@"XGTrace", @"DPSwindow: %@ %d", NSStringFromRect(frame), (int)type);
/* Create the window structure and set the style early so we can use it to
convert frames. */
window = NSAllocateCollectable(sizeof(gswindow_device_t), NSScannedOption);
memset(window, '\0', sizeof(gswindow_device_t));
/*
* FIXME - should this be protected by a lock for thread safety?
* generate a unique tag for this new window.
*/
do
{
last_win_num++;
}
while (last_win_num == 0 || WINDOW_WITH_TAG(last_win_num) != 0);
window->number = last_win_num;
// Insert window into the mapping
NSMapInsert(windowmaps, (void*)(uintptr_t)window->ident, window);
NSMapInsert(windowtags, (void*)(uintptr_t)window->number, window);
[self _setWindowOwnedByServer: window->number];
return window->number;
}
- (int) nativeWindow: (void *)winref : (NSRect*)frame : (NSBackingStoreType*)type
: (unsigned int*)style : (int*)screen
{
return 0;
}
- (void) termwindow: (int)win
{
}
/*
* Return the offsets between the window content-view and it's frame
* depending on the window style.
*/
- (void) styleoffsets: (float *) l : (float *) r : (float *) t : (float *) b
: (unsigned int) style
{
[self styleoffsets: l : r : t : b : style : (Window) 0];
}
- (void) styleoffsets: (float *) l : (float *) r : (float *) t : (float *) b
: (unsigned int) style : (Window) win
{
}
- (void) stylewindow: (unsigned int)style : (int) win
{
}
- (void) setbackgroundcolor: (NSColor *)color : (int)win
{
}
- (void) windowbacking: (NSBackingStoreType)type : (int) win
{
}
- (void) titlewindow: (NSString *)window_title : (int) win
{
}
- (void) docedited: (int)edited : (int) win
{
}
- (BOOL) appOwnsMiniwindow
{
return generic.flags.appOwnsMiniwindow;
}
- (void) miniwindow: (int) win
{
}
/**
Make sure we have the most up-to-date window information and then
make sure the context has our new information
*/
- (void) setWindowdevice: (int)win forContext: (NSGraphicsContext *)ctxt
{
}
-(int) _createAppIconPixmaps
{
return 1;
}
- (void) orderwindow: (int)op : (int)otherWin : (int)winNum
{
}
#define ALPHA_THRESHOLD 158
/* Restrict the displayed part of the window to the given image.
This only yields usefull results if the window is borderless and
displays the image itself */
- (void) restrictWindow: (int)win toImage: (NSImage*)image
{
}
/* This method is a fast implementation of move that only works
correctly for borderless windows. Use with caution. */
- (void) movewindow: (NSPoint)loc : (int)win
{
}
- (void) placewindow: (NSRect)rect : (int)win
{
}
- (BOOL) findwindow: (NSPoint)loc : (int) op : (int) otherWin : (NSPoint *)floc
: (int*) winFound
{
return NO;
}
- (NSRect) windowbounds: (int)win
{
return NSMakeRect(0, 0, 0, 0);
}
- (void) setwindowlevel: (int)level : (int)win
{
}
- (int) windowlevel: (int)win
{
return 0;
}
- (NSArray *) windowlist
{
return [NSMutableArray array];
}
- (int) windowdepth: (int)win
{
return 0;
}
- (void) setmaxsize: (NSSize)size : (int)win
{
}
- (void) setminsize: (NSSize)size : (int)win
{
}
- (void) setresizeincrements: (NSSize)size : (int)win
{
}
// process expose event
- (void) _addExposedRectangle: (XRectangle)rectangle : (int)win : (BOOL) ignoreBacking
{
}
- (void) flushwindowrect: (NSRect)rect : (int)win
{
}
// handle X expose events
- (void) _processExposedRectangles: (int)win
{
}
- (BOOL) capturemouse: (int)win
{
return NO;
}
- (void) setMouseLocation: (NSPoint)mouseLocation onScreen: (int)aScreen
{
}
- (void) setinputfocus: (int)win
{
}
/*
* Instruct window manager that the specified window is 'key', 'main', or
* just a normal window.
*/
- (void) setinputstate: (int)st : (int)win
{
}
/** Sets the transparancy value for the whole window */
- (void) setalpha: (float)alpha : (int) win
{
}
- (float) getAlpha: (int)win
{
return 1;
}
- (void *) serverDevice
{
return dpy;
}
- (void *) windowDevice: (int)win
{
return (void *)NULL;
}
/* Cursor Ops */
static BOOL cursor_hidden = NO;
- (Cursor) _blankCursor
{
return None;
}
/*
set the cursor for a newly created window.
*/
- (void) _initializeCursorForXWindow: (Window) win
{
}
/*
set cursor on all XWindows we own. if `set' is NO
the cursor is unset on all windows.
Normally the cursor `c' correspond to the [NSCursor currentCursor]
The only exception should be when the cursor is hidden.
In that case `c' will be a blank cursor.
*/
- (void) _DPSsetcursor: (Cursor)c : (BOOL)set
{
}
#define ALPHA_THRESHOLD 158
Pixmap
xgps_cursor_mask(Display *xdpy, Drawable draw, const unsigned char *data,
int w, int h, int colors)
{
return 0;
}
Pixmap
xgps_cursor_image(Display *xdpy, Drawable draw, const unsigned char *data,
int w, int h, int colors, XColor *fg, XColor *bg)
{
return None;
}
- (void) hidecursor
{
cursor_hidden = YES;
}
- (void) showcursor
{
cursor_hidden = NO;
}
- (void) standardcursor: (int)style : (void **)cid
{
}
- (void) imagecursor: (NSPoint)hotp : (NSImage *)image : (void **)cid
{
}
- (void) recolorcursor: (NSColor *)fg : (NSColor *)bg : (void*) cid
{
}
- (void) setcursor: (void*) cid
{
}
- (void) freecursor: (void*) cid
{
}
- (NSArray *)screenList
{
NSMutableArray *screens = [NSMutableArray arrayWithCapacity: 1];
[screens addObject: [NSNumber numberWithInt: defScreen]];
return screens;
}
- (NSWindowDepth) windowDepthForScreen: (int) screen_num
{
return 0;
}
- (const NSWindowDepth *) availableDepthsForScreen: (int) screen_num
{
return NULL;
}
- (NSSize) resolutionForScreen: (int)screen_num
{
// NOTE:
// -gui now trusts the return value of resolutionForScreen:,
// so if it is not {72, 72} then the entire UI will be scaled.
//
// I commented out the implementation below because it may not
// be safe to use the DPI value we get from the X server.
// (i.e. I don't know if it will be a "fake" DPI like 72 or 96,
// or a real measurement reported from the monitor's firmware
// (possibly incorrect?))
// More research needs to be done.
return NSMakeSize(72, 72);
}
- (NSRect) boundsForScreen: (int)screen
{
return NSMakeRect(0, 0, 400, 400);
}
- (NSImage *) iconTileImage
{
return nil;
}
- (NSSize) iconSize
{
return [super iconSize];
}
- (unsigned int) numberOfDesktops: (int)screen
{
return 1;
}
- (NSArray *) namesOfDesktops: (int)screen
{
return nil;
}
- (unsigned int) desktopNumberForScreen: (int)screen
{
return 0;
}
- (void) setDesktopNumber: (unsigned int)workspace forScreen: (int)screen
{
}
- (unsigned int) desktopNumberForWindow: (int)win
{
return 0;
}
- (void) setDesktopNumber: (unsigned int)workspace forWindow: (int)win
{
}
- (void) setShadow: (BOOL)hasShadow : (int)win
{
}
- (BOOL) hasShadow: (int)win
{
return NO;
}
/*
* Check whether the window is miniaturized according to the ICCCM window
* state property.
*/
- (int) _wm_state: (Window)win
{
return WithdrawnState;
}
/*
* Check whether the EWMH window state includes the _NET_WM_STATE_HIDDEN
* state. On EWMH, a window is iconified if it is iconic state and the
* _NET_WM_STATE_HIDDEN is present.
*/
- (BOOL) _ewmh_isHidden: (Window)win
{
return NO;
}
- (void) setParentWindow: (int)parentWin
forChildWindow: (int)childWin
{
}
- (void) setIgnoreMouse: (BOOL)ignoreMouse : (int)win
{
}
@end