mirror of
https://github.com/gnustep/libs-back.git
synced 2025-02-24 12:21:34 +00:00
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/back/trunk@18367 72102866-910b-0410-8b05-ffd578937521
2863 lines
76 KiB
Objective-C
2863 lines
76 KiB
Objective-C
/* XGServerWindows - methods for window/screen handling
|
|
|
|
Copyright (C) 1999 Free Software Foundation, Inc.
|
|
|
|
Written by: Adam Fedor <fedor@gnu.org>
|
|
Date: Nov 1999
|
|
|
|
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 Library 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
|
|
Library General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public
|
|
License along with this library; if not, write to the Free
|
|
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include <math.h>
|
|
#include <Foundation/NSString.h>
|
|
#include <Foundation/NSArray.h>
|
|
#include <Foundation/NSValue.h>
|
|
#include <Foundation/NSProcessInfo.h>
|
|
#include <Foundation/NSUserDefaults.h>
|
|
#include <Foundation/NSAutoreleasePool.h>
|
|
#include <Foundation/NSDebug.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
|
|
|
|
#ifdef HAVE_WRASTER_H
|
|
#include "wraster.h"
|
|
#else
|
|
#include "x11/wraster.h"
|
|
#endif
|
|
#include <X11/cursorfont.h>
|
|
|
|
#include <X11/extensions/shape.h>
|
|
|
|
#include "x11/XGDragView.h"
|
|
#include "x11/XGInputServer.h"
|
|
|
|
#define ROOT generic.appRootWindow
|
|
|
|
/*
|
|
* Name for application root window.
|
|
*/
|
|
static char *rootName = 0;
|
|
|
|
#define WINDOW_WITH_TAG(windowNumber) (gswindow_device_t *)NSMapGet(windowtags, (void *)windowNumber)
|
|
|
|
/* Current mouse grab window */
|
|
static gswindow_device_t *grab_window = NULL;
|
|
|
|
/* Keep track of windows */
|
|
static NSMapTable *windowmaps = NULL;
|
|
static NSMapTable *windowtags = NULL;
|
|
|
|
@interface NSCursor (BackendPrivate)
|
|
- (void *)_cid;
|
|
@end
|
|
|
|
void __objc_xgcontextwindow_linking (void)
|
|
{
|
|
}
|
|
|
|
/*
|
|
* The next two functions derived from WindowMaker by Alfredo K. Kojima
|
|
*/
|
|
static unsigned char*
|
|
PropGetCheckProperty(Display *dpy, Window window, Atom hint, Atom type,
|
|
int format, int count, int *retCount)
|
|
{
|
|
Atom type_ret;
|
|
int fmt_ret;
|
|
unsigned long nitems_ret;
|
|
unsigned long bytes_after_ret;
|
|
unsigned char *data;
|
|
int tmp;
|
|
|
|
if (count <= 0)
|
|
tmp = 0xffffff;
|
|
else
|
|
tmp = count;
|
|
|
|
if (XGetWindowProperty(dpy, window, hint, 0, tmp, False, type,
|
|
&type_ret, &fmt_ret, &nitems_ret, &bytes_after_ret,
|
|
(unsigned char **)&data)!=Success || !data)
|
|
return NULL;
|
|
|
|
if ((type!=AnyPropertyType && type!=type_ret)
|
|
|| (count > 0 && nitems_ret != (unsigned long)count)
|
|
|| (format != 0 && format != fmt_ret))
|
|
{
|
|
XFree(data);
|
|
return NULL;
|
|
}
|
|
|
|
if (retCount)
|
|
*retCount = nitems_ret;
|
|
|
|
return data;
|
|
}
|
|
|
|
static void
|
|
setNormalHints(Display *d, gswindow_device_t *w)
|
|
{
|
|
if (w->siz_hints.flags & (USPosition | PPosition))
|
|
NSDebugLLog(@"XGTrace", @"Hint posn %d: %d, %d",
|
|
w->number, w->siz_hints.x, w->siz_hints.y);
|
|
if (w->siz_hints.flags & (USSize | PSize))
|
|
NSDebugLLog(@"XGTrace", @"Hint size %d: %d, %d",
|
|
w->number, w->siz_hints.width, w->siz_hints.height);
|
|
if (w->siz_hints.flags & PMinSize)
|
|
NSDebugLLog(@"XGTrace", @"Hint mins %d: %d, %d",
|
|
w->number, w->siz_hints.min_width, w->siz_hints.min_height);
|
|
if (w->siz_hints.flags & PMaxSize)
|
|
NSDebugLLog(@"XGTrace", @"Hint maxs %d: %d, %d",
|
|
w->number, w->siz_hints.max_width, w->siz_hints.max_height);
|
|
if (w->siz_hints.flags & PResizeInc)
|
|
NSDebugLLog(@"XGTrace", @"Hint incr %d: %d, %d",
|
|
w->number, w->siz_hints.width_inc, w->siz_hints.height_inc);
|
|
XSetWMNormalHints(d, w->ident, &w->siz_hints);
|
|
}
|
|
|
|
/*
|
|
* Setting Motif Hints for Window Managers (Nicola Pero, July 2000)
|
|
*/
|
|
|
|
/*
|
|
* Motif window hints to communicate to a window manager
|
|
* that we want a window to have a titlebar/resize button/etc.
|
|
*/
|
|
|
|
/* Motif window hints struct */
|
|
typedef struct {
|
|
unsigned long flags;
|
|
unsigned long functions;
|
|
unsigned long decorations;
|
|
long input_mode;
|
|
unsigned long status;
|
|
} MwmHints;
|
|
|
|
/* Number of entries in the struct */
|
|
#define PROP_MWM_HINTS_ELEMENTS 5
|
|
|
|
/* Now for each field in the struct, meaningful stuff to put in: */
|
|
|
|
/* flags */
|
|
#define MWM_HINTS_FUNCTIONS (1L << 0)
|
|
#define MWM_HINTS_DECORATIONS (1L << 1)
|
|
#define MWM_HINTS_INPUT_MODE (1L << 2)
|
|
#define MWM_HINTS_STATUS (1L << 3)
|
|
|
|
/* functions */
|
|
#define MWM_FUNC_ALL (1L << 0)
|
|
#define MWM_FUNC_RESIZE (1L << 1)
|
|
#define MWM_FUNC_MOVE (1L << 2)
|
|
#define MWM_FUNC_MINIMIZE (1L << 3)
|
|
#define MWM_FUNC_MAXIMIZE (1L << 4)
|
|
#define MWM_FUNC_CLOSE (1L << 5)
|
|
|
|
/* decorations */
|
|
#define MWM_DECOR_ALL (1L << 0)
|
|
#define MWM_DECOR_BORDER (1L << 1)
|
|
#define MWM_DECOR_RESIZEH (1L << 2)
|
|
#define MWM_DECOR_TITLE (1L << 3)
|
|
#define MWM_DECOR_MENU (1L << 4)
|
|
#define MWM_DECOR_MINIMIZE (1L << 5)
|
|
#define MWM_DECOR_MAXIMIZE (1L << 6)
|
|
|
|
/* We don't use the input_mode and status fields */
|
|
|
|
/* The atom */
|
|
#define _XA_MOTIF_WM_HINTS "_MOTIF_WM_HINTS"
|
|
|
|
/* Now the code */
|
|
|
|
/* Set the style `styleMask' for the XWindow `window' using motif
|
|
* window hints. This makes an X call, please make sure you do it
|
|
* only once.
|
|
*/
|
|
static void setWindowHintsForStyle (Display *dpy, Window window,
|
|
unsigned int styleMask)
|
|
{
|
|
MwmHints *hints;
|
|
BOOL needToFreeHints = YES;
|
|
Atom type_ret;
|
|
int format_ret, success;
|
|
unsigned long nitems_ret;
|
|
unsigned long bytes_after_ret;
|
|
static Atom mwhints_atom = None;
|
|
|
|
/* Initialize the atom if needed */
|
|
if (mwhints_atom == None)
|
|
mwhints_atom = XInternAtom (dpy,_XA_MOTIF_WM_HINTS, False);
|
|
|
|
/* Get the already-set window hints */
|
|
success = XGetWindowProperty (dpy, window, mwhints_atom, 0,
|
|
sizeof (MwmHints) / sizeof (long),
|
|
False, AnyPropertyType, &type_ret, &format_ret,
|
|
&nitems_ret, &bytes_after_ret,
|
|
(unsigned char **)&hints);
|
|
|
|
/* If no window hints were set, create new hints to 0 */
|
|
if (success != Success || type_ret == None)
|
|
{
|
|
needToFreeHints = NO;
|
|
hints = alloca (sizeof (MwmHints));
|
|
memset (hints, 0, sizeof (MwmHints));
|
|
}
|
|
|
|
/* Remove the hints we want to change */
|
|
hints->flags &= ~MWM_HINTS_DECORATIONS;
|
|
hints->flags &= ~MWM_HINTS_FUNCTIONS;
|
|
hints->decorations = 0;
|
|
hints->functions = 0;
|
|
|
|
/* Now add to the hints from the styleMask */
|
|
if (styleMask == NSBorderlessWindowMask)
|
|
{
|
|
hints->flags |= MWM_HINTS_DECORATIONS;
|
|
hints->flags |= MWM_HINTS_FUNCTIONS;
|
|
hints->decorations = 0;
|
|
hints->functions = 0;
|
|
}
|
|
else
|
|
{
|
|
/* These need to be on all windows except mini and icon windows,
|
|
where they are specifically set to 0 (see below) */
|
|
hints->flags |= MWM_HINTS_DECORATIONS;
|
|
hints->decorations |= (MWM_DECOR_TITLE | MWM_DECOR_BORDER);
|
|
if (styleMask & NSTitledWindowMask)
|
|
{
|
|
// Without this, iceWM does not let you move the window!
|
|
// [idem below]
|
|
hints->flags |= MWM_HINTS_FUNCTIONS;
|
|
hints->functions |= MWM_FUNC_MOVE;
|
|
}
|
|
if (styleMask & NSClosableWindowMask)
|
|
{
|
|
hints->flags |= MWM_HINTS_FUNCTIONS;
|
|
hints->functions |= MWM_FUNC_CLOSE;
|
|
hints->functions |= MWM_FUNC_MOVE;
|
|
}
|
|
if (styleMask & NSMiniaturizableWindowMask)
|
|
{
|
|
hints->flags |= MWM_HINTS_DECORATIONS;
|
|
hints->flags |= MWM_HINTS_FUNCTIONS;
|
|
hints->decorations |= MWM_DECOR_MINIMIZE;
|
|
hints->functions |= MWM_FUNC_MINIMIZE;
|
|
hints->functions |= MWM_FUNC_MOVE;
|
|
}
|
|
if (styleMask & NSResizableWindowMask)
|
|
{
|
|
hints->flags |= MWM_HINTS_DECORATIONS;
|
|
hints->flags |= MWM_HINTS_FUNCTIONS;
|
|
hints->decorations |= MWM_DECOR_RESIZEH;
|
|
hints->decorations |= MWM_DECOR_MAXIMIZE;
|
|
hints->functions |= MWM_FUNC_RESIZE;
|
|
hints->functions |= MWM_FUNC_MAXIMIZE;
|
|
hints->functions |= MWM_FUNC_MOVE;
|
|
}
|
|
if (styleMask & NSIconWindowMask)
|
|
{
|
|
// FIXME
|
|
hints->flags |= MWM_HINTS_DECORATIONS;
|
|
hints->flags |= MWM_HINTS_FUNCTIONS;
|
|
hints->decorations = 0;
|
|
hints->functions = 0;
|
|
}
|
|
if (styleMask & NSMiniWindowMask)
|
|
{
|
|
// FIXME
|
|
hints->flags |= MWM_HINTS_DECORATIONS;
|
|
hints->flags |= MWM_HINTS_FUNCTIONS;
|
|
hints->decorations = 0;
|
|
hints->functions = 0;
|
|
}
|
|
}
|
|
|
|
/* Set the hints */
|
|
XChangeProperty (dpy, window, mwhints_atom, mwhints_atom, 32,
|
|
PropModeReplace, (unsigned char *)hints,
|
|
sizeof (MwmHints) / sizeof (long));
|
|
|
|
/* Free the hints if allocated by the X server for us */
|
|
if (needToFreeHints == YES)
|
|
XFree (hints);
|
|
}
|
|
|
|
/*
|
|
* End of motif hints for window manager code
|
|
*/
|
|
|
|
@interface NSEvent (WindowHack)
|
|
- (void) _patchLocation: (NSPoint)loc;
|
|
@end
|
|
|
|
@implementation NSEvent (WindowHack)
|
|
- (void) _patchLocation: (NSPoint)loc
|
|
{
|
|
location_point = loc;
|
|
}
|
|
@end
|
|
|
|
@implementation XGServer (WindowOps)
|
|
|
|
/*
|
|
* 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;
|
|
Window x;
|
|
gswindow_device_t *d;
|
|
|
|
enumerator = NSEnumerateMapTable(windowmaps);
|
|
while (NSNextMapEnumeratorPair(&enumerator, (void**)&x, (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.
|
|
*/
|
|
- (NSRect) _OSFrameToXFrame: (NSRect)o for: (void*)window
|
|
{
|
|
gswindow_device_t *win = (gswindow_device_t*)window;
|
|
NSRect x;
|
|
float t, b, l, r;
|
|
|
|
[self styleoffsets: &l : &r : &t : &b : win->win_attrs.window_style];
|
|
|
|
x.size.width = o.size.width - l - r;
|
|
x.size.height = o.size.height - t - b;
|
|
x.origin.x = o.origin.x + l;
|
|
x.origin.y = o.origin.y + o.size.height - t;
|
|
x.origin.y = DisplayHeight(dpy, win->screen) - x.origin.y;
|
|
NSDebugLLog(@"Frame", @"O2X %d, %@, %@", win->number,
|
|
NSStringFromRect(o), NSStringFromRect(x));
|
|
return x;
|
|
}
|
|
|
|
/*
|
|
* Convert a window frame in OpenStep absolute screen coordinates to
|
|
* a frame suitable for setting X hints for a window manager.
|
|
*/
|
|
- (NSRect) _OSFrameToXHints: (NSRect)o for: (void*)window
|
|
{
|
|
gswindow_device_t *win = (gswindow_device_t*)window;
|
|
NSRect x;
|
|
float t, b, l, r;
|
|
|
|
[self styleoffsets: &l : &r : &t : &b : win->win_attrs.window_style];
|
|
|
|
x.size.width = o.size.width - l - r;
|
|
x.size.height = o.size.height - t - b;
|
|
x.origin.x = o.origin.x;
|
|
x.origin.y = o.origin.y + o.size.height;
|
|
x.origin.y = DisplayHeight(dpy, win->screen) - x.origin.y;
|
|
NSDebugLLog(@"Frame", @"O2H %d, %@, %@", win->number,
|
|
NSStringFromRect(o), NSStringFromRect(x));
|
|
return x;
|
|
}
|
|
|
|
/*
|
|
* Convert a window frame in X coordinates relative to the X-window to a frame
|
|
* in OpenStep coordinates relative to the window by flipping.
|
|
*/
|
|
- (NSRect) _XWinFrameToOSWinFrame: (NSRect)x for: (void*)window
|
|
{
|
|
gswindow_device_t *win = (gswindow_device_t*)window;
|
|
NSRect o;
|
|
o.size.width = x.size.width;
|
|
o.size.height = x.size.height;
|
|
o.origin.x = x.origin.x;
|
|
o.origin.y = win->siz_hints.height - x.origin.y;
|
|
o.origin.y = o.origin.y - o.size.height;
|
|
NSDebugLLog(@"GGFrame", @"%@ %@", NSStringFromRect(x), NSStringFromRect(o));
|
|
return o;
|
|
}
|
|
|
|
/*
|
|
* 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
|
|
{
|
|
gswindow_device_t *win = (gswindow_device_t*)window;
|
|
NSRect o;
|
|
float t, b, l, r;
|
|
|
|
[self styleoffsets: &l : &r : &t : &b : win->win_attrs.window_style];
|
|
o.size.width = x.size.width + l + r;
|
|
o.size.height = x.size.height + t + b;
|
|
o.origin.x = x.origin.x - l;
|
|
o.origin.y = DisplayHeight(dpy, win->screen) - x.origin.y;
|
|
o.origin.y = o.origin.y - o.size.height + t;
|
|
NSDebugLLog(@"Frame", @"X2O %d, %@, %@", win->number,
|
|
NSStringFromRect(x), NSStringFromRect(o));
|
|
return o;
|
|
}
|
|
|
|
|
|
- (XGWMProtocols) _checkWindowManager
|
|
{
|
|
int wmflags;
|
|
Window root;
|
|
Window *win;
|
|
Atom *data;
|
|
Atom atom;
|
|
int count;
|
|
|
|
root = DefaultRootWindow(dpy);
|
|
wmflags = XGWM_UNKNOWN;
|
|
|
|
/* Check for WindowMaker */
|
|
atom = XInternAtom(dpy, "_WINDOWMAKER_WM_PROTOCOLS", False);
|
|
data = (Atom*)PropGetCheckProperty(dpy, root, atom, XA_ATOM, 32, -1, &count);
|
|
if (data != 0)
|
|
{
|
|
Atom noticeboard;
|
|
int i = 0;
|
|
|
|
noticeboard = XInternAtom(dpy, "_WINDOWMAKER_NOTICEBOARD", False);
|
|
while (i < count && data[i] != noticeboard)
|
|
{
|
|
i++;
|
|
}
|
|
XFree(data);
|
|
|
|
if (i < count)
|
|
{
|
|
Window *win;
|
|
void *d;
|
|
|
|
win = (Window*)PropGetCheckProperty(dpy, root,
|
|
noticeboard, XA_WINDOW, 32, -1, &count);
|
|
|
|
if (win != 0)
|
|
{
|
|
d = PropGetCheckProperty(dpy, *win, noticeboard,
|
|
XA_WINDOW, 32, 1, NULL);
|
|
if (d != 0)
|
|
{
|
|
XFree(d);
|
|
wmflags |= XGWM_WINDOWMAKER;
|
|
}
|
|
XFree(win);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
wmflags |= XGWM_WINDOWMAKER;
|
|
}
|
|
}
|
|
|
|
/* Now check for Gnome */
|
|
atom = XInternAtom(dpy, "_WIN_SUPPORTING_WM_CHECK", False);
|
|
win = (Window*)PropGetCheckProperty(dpy, root, atom,
|
|
XA_CARDINAL, 32, -1, &count);
|
|
if (win != 0)
|
|
{
|
|
Window *win1;
|
|
|
|
win1 = (Window*)PropGetCheckProperty(dpy, *win, atom,
|
|
XA_CARDINAL, 32, -1, &count);
|
|
// If the two are not identical, the flag on the root window, was
|
|
// a left over from an old window manager.
|
|
if (win1 && *win1 == *win)
|
|
{
|
|
wmflags |= XGWM_GNOME;
|
|
|
|
generic.wintypes.win_type_atom =
|
|
XInternAtom(dpy, "_WIN_LAYER", False);
|
|
}
|
|
if (win1)
|
|
{
|
|
XFree(win1);
|
|
}
|
|
XFree(win);
|
|
}
|
|
|
|
/* Now check for NET (EWMH) compliant window manager */
|
|
atom = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False);
|
|
win = (Window*)PropGetCheckProperty(dpy, root, atom,
|
|
XA_WINDOW, 32, -1, &count);
|
|
|
|
if (win != 0)
|
|
{
|
|
Window *win1;
|
|
|
|
win1 = (Window*)PropGetCheckProperty(dpy, *win, atom,
|
|
XA_WINDOW, 32, -1, &count);
|
|
// If the two are not identical, the flag on the root window, was
|
|
// a left over from an old window manager.
|
|
if (win1 && *win1 == *win)
|
|
{
|
|
wmflags |= XGWM_EWMH;
|
|
|
|
// Store window type Atoms for this WM
|
|
generic.wintypes.win_type_atom =
|
|
XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
|
|
generic.wintypes.win_desktop_atom =
|
|
XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DESKTOP", False);
|
|
generic.wintypes.win_dock_atom =
|
|
XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DOCK", False);
|
|
generic.wintypes.win_floating_atom =
|
|
XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_TOOLBAR", False);
|
|
generic.wintypes.win_menu_atom =
|
|
XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_MENU", False);
|
|
generic.wintypes.win_modal_atom =
|
|
XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
|
|
generic.wintypes.win_normal_atom =
|
|
XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_NORMAL", False);
|
|
// New in wmspec 1.2
|
|
generic.wintypes.win_utility_atom =
|
|
XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_UTILITY", False);
|
|
generic.wintypes.win_splash_atom =
|
|
XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_SPLASH", False);
|
|
//KDE extensions
|
|
generic.wintypes.win_override_atom =
|
|
XInternAtom(dpy, "_KDE_NET_WM_WINDOW_TYPE_OVERRIDE", False);
|
|
generic.wintypes.win_topmenu_atom =
|
|
XInternAtom(dpy, "_KDE_NET_WM_WINDOW_TYPE_TOPMENU", False);
|
|
}
|
|
if (win1)
|
|
{
|
|
XFree(win1);
|
|
}
|
|
XFree(win);
|
|
}
|
|
|
|
NSDebugLLog(@"WM",
|
|
@"WM Protocols: WindowMaker=(%s) GNOME=(%s) KDE=(%s) EWMH=(%s)",
|
|
(wmflags & XGWM_WINDOWMAKER) ? "YES" : "NO",
|
|
(wmflags & XGWM_GNOME) ? "YES" : "NO",
|
|
(wmflags & XGWM_KDE) ? "YES" : "NO",
|
|
(wmflags & XGWM_EWMH) ? "YES" : "NO");
|
|
|
|
return wmflags;
|
|
}
|
|
|
|
- (gswindow_device_t *)_rootWindowForScreen: (int)screen
|
|
{
|
|
int x, y, width, height;
|
|
gswindow_device_t *window;
|
|
|
|
/* Screen number is negative to avoid conflict with windows */
|
|
window = WINDOW_WITH_TAG(-screen);
|
|
if (window)
|
|
return window;
|
|
|
|
window = objc_malloc(sizeof(gswindow_device_t));
|
|
memset(window, '\0', sizeof(gswindow_device_t));
|
|
|
|
window->display = dpy;
|
|
window->screen = screen;
|
|
window->ident = RootWindow(dpy, screen);
|
|
window->root = window->ident;
|
|
window->type = NSBackingStoreNonretained;
|
|
window->number = -screen;
|
|
window->map_state = IsViewable;
|
|
window->visibility = -1;
|
|
if (window->ident)
|
|
XGetGeometry(dpy, window->ident, &window->root,
|
|
&x, &y, &width, &height,
|
|
&window->border, &window->depth);
|
|
|
|
window->xframe = NSMakeRect(x, y, width, height);
|
|
NSMapInsert (windowtags, (void*)window->number, window);
|
|
NSMapInsert (windowmaps, (void*)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
|
|
{
|
|
int numButtons;
|
|
unsigned char mouseNumbers[5];
|
|
unsigned char buttons[5] = {
|
|
Button1,
|
|
Button2,
|
|
Button3,
|
|
Button4,
|
|
Button5
|
|
};
|
|
int masks[5] = {
|
|
Button1Mask,
|
|
Button2Mask,
|
|
Button3Mask,
|
|
Button4Mask,
|
|
Button5Mask
|
|
};
|
|
/*
|
|
* Get pointer information - so we know which mouse buttons we have.
|
|
* With a two button
|
|
*/
|
|
numButtons = XGetPointerMapping(dpy, mouseNumbers, 5);
|
|
if (numButtons > 5)
|
|
{
|
|
NSLog(@"Warning - mouse/pointer seems to have more than 5 buttons"
|
|
@" - just using one to five");
|
|
numButtons = 5;
|
|
}
|
|
generic.lMouse = buttons[0];
|
|
generic.lMouseMask = masks[0];
|
|
if (numButtons >= 5)
|
|
{
|
|
generic.upMouse = buttons[3];
|
|
generic.downMouse = buttons[4];
|
|
generic.rMouse = buttons[2];
|
|
generic.rMouseMask = masks[2];
|
|
generic.mMouse = buttons[1];
|
|
generic.mMouseMask = masks[1];
|
|
}
|
|
else if (numButtons == 3)
|
|
{
|
|
// FIXME: Button4 and Button5 are ScrollWheel up and ScrollWheel down
|
|
// generic.rMouse = buttons[numButtons-1];
|
|
// generic.rMouseMask = masks[numButtons-1];
|
|
generic.upMouse = 0;
|
|
generic.downMouse = 0;
|
|
generic.rMouse = buttons[2];
|
|
generic.rMouseMask = masks[2];
|
|
generic.mMouse = buttons[1];
|
|
generic.mMouseMask = masks[1];
|
|
}
|
|
else if (numButtons == 2)
|
|
{
|
|
generic.upMouse = 0;
|
|
generic.downMouse = 0;
|
|
generic.rMouse = buttons[1];
|
|
generic.rMouseMask = masks[1];
|
|
generic.mMouse = 0;
|
|
generic.mMouseMask = 0;
|
|
}
|
|
else if (numButtons == 1)
|
|
{
|
|
generic.upMouse = 0;
|
|
generic.downMouse = 0;
|
|
generic.rMouse = 0;
|
|
generic.rMouseMask = 0;
|
|
generic.mMouse = 0;
|
|
generic.mMouseMask = 0;
|
|
}
|
|
else
|
|
{
|
|
NSLog(@"Warning - mouse/pointer seems to have NO buttons");
|
|
}
|
|
}
|
|
|
|
- (void) _setupRootWindow
|
|
{
|
|
NSProcessInfo *pInfo = [NSProcessInfo processInfo];
|
|
NSArray *args;
|
|
unsigned int i;
|
|
unsigned int argc;
|
|
char **argv;
|
|
XClassHint classhint;
|
|
XTextProperty windowName;
|
|
NSUserDefaults *defs;
|
|
const char *host_name = [[pInfo hostName] UTF8String];
|
|
|
|
/*
|
|
* Initialize time of last events to be the start of time - not
|
|
* the current time!
|
|
*/
|
|
if (CurrentTime == 0)
|
|
{
|
|
generic.lastClick = 1;
|
|
generic.lastMotion = 1;
|
|
generic.lastTime = 1;
|
|
}
|
|
|
|
/*
|
|
* Set up standard atoms.
|
|
*/
|
|
generic.protocols_atom = XInternAtom(dpy, "WM_PROTOCOLS", False);
|
|
generic.take_focus_atom = XInternAtom(dpy, "WM_TAKE_FOCUS", False);
|
|
generic.delete_win_atom = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
|
|
generic.miniaturize_atom
|
|
= XInternAtom(dpy, "_GNUSTEP_WM_MINIATURIZE_WINDOW", False);
|
|
generic.win_decor_atom = XInternAtom(dpy,"_GNUSTEP_WM_ATTR", False);
|
|
generic.titlebar_state_atom
|
|
= XInternAtom(dpy, "_GNUSTEP_TITLEBAR_STATE", False);
|
|
|
|
[self _setupMouse];
|
|
[self _checkWindowlist];
|
|
|
|
/*
|
|
* determine window manager in use.
|
|
*/
|
|
generic.wm = [self _checkWindowManager];
|
|
|
|
/*
|
|
* Now check user defaults.
|
|
*/
|
|
defs = [NSUserDefaults standardUserDefaults];
|
|
generic.flags.useWindowMakerIcons = NO;
|
|
if ((generic.wm & XGWM_WINDOWMAKER) != 0)
|
|
{
|
|
generic.flags.useWindowMakerIcons = YES;
|
|
if ([defs stringForKey: @"UseWindowMakerIcons"] != nil
|
|
&& [defs boolForKey: @"UseWindowMakerIcons"] == NO)
|
|
{
|
|
generic.flags.useWindowMakerIcons = NO;
|
|
}
|
|
}
|
|
generic.flags.appOwnsMiniwindow = YES;
|
|
if ([defs stringForKey: @"GSAppOwnsMiniwindow"] != nil
|
|
&& [defs boolForKey: @"GSAppOwnsMiniwindow"] == NO)
|
|
{
|
|
generic.flags.appOwnsMiniwindow = NO;
|
|
}
|
|
generic.flags.doubleParentWindow = NO;
|
|
if ([defs stringForKey: @"GSDoubleParentWindows"] != nil
|
|
&& [defs boolForKey: @"GSDoubleParentWindows"] == YES)
|
|
{
|
|
generic.flags.doubleParentWindow = YES;
|
|
}
|
|
|
|
|
|
/*
|
|
* make app root window
|
|
*/
|
|
ROOT = XCreateSimpleWindow(dpy,RootWindow(dpy,defScreen),0,0,1,1,0,0,0);
|
|
|
|
/*
|
|
* set hints for root window
|
|
*/
|
|
{
|
|
XWMHints gen_hints;
|
|
|
|
gen_hints.flags = WindowGroupHint | StateHint;
|
|
gen_hints.initial_state = WithdrawnState;
|
|
gen_hints.window_group = ROOT;
|
|
XSetWMHints(dpy, ROOT, &gen_hints);
|
|
}
|
|
|
|
/*
|
|
* Mark this as a GNUstep app with the current application name.
|
|
*/
|
|
if (rootName == 0)
|
|
{
|
|
const char *str = [[pInfo processName] UTF8String];
|
|
|
|
rootName = objc_malloc(strlen(str) + 1);
|
|
strcpy(rootName, str);
|
|
}
|
|
classhint.res_name = rootName;
|
|
classhint.res_class = "GNUstep";
|
|
XSetClassHint(dpy, ROOT, &classhint);
|
|
|
|
/*
|
|
* Set app name as root window title - probably unused unless
|
|
* the window manager wants to keep us in a menu or something like that.
|
|
*/
|
|
XStringListToTextProperty((char**)&classhint.res_name, 1, &windowName);
|
|
XSetWMName(dpy, ROOT, &windowName);
|
|
XSetWMIconName(dpy, ROOT, &windowName);
|
|
XFree(windowName.value);
|
|
|
|
/*
|
|
* Record the information used to start this app.
|
|
* If we have a user default set up (eg. by the openapp script) use it.
|
|
* otherwise use the process arguments.
|
|
*/
|
|
args = [defs arrayForKey: @"GSLaunchCommand"];
|
|
if (args == nil)
|
|
{
|
|
args = [pInfo arguments];
|
|
}
|
|
argc = [args count];
|
|
argv = (char**)objc_malloc(argc*sizeof(char*));
|
|
for (i = 0; i < argc; i++)
|
|
{
|
|
argv[i] = (char*)[[args objectAtIndex: i] UTF8String];
|
|
}
|
|
XSetCommand(dpy, ROOT, argv, argc);
|
|
objc_free(argv);
|
|
|
|
// Store the host name of the machine we a running on
|
|
XStringListToTextProperty((char**)&host_name, 1, &windowName);
|
|
XSetWMClientMachine(dpy, ROOT, &windowName);
|
|
XFree(windowName.value);
|
|
|
|
// Always send GNUstepWMAttributes
|
|
{
|
|
GNUstepWMAttributes win_attrs;
|
|
|
|
/*
|
|
* Tell WindowMaker not to set up an app icon for us - we'll make our own.
|
|
*/
|
|
win_attrs.flags = GSExtraFlagsAttr;
|
|
win_attrs.extra_flags = GSNoApplicationIconFlag;
|
|
XChangeProperty(dpy, ROOT,
|
|
generic.win_decor_atom, generic.win_decor_atom,
|
|
32, PropModeReplace, (unsigned char *)&win_attrs,
|
|
sizeof(GNUstepWMAttributes)/sizeof(CARD32));
|
|
}
|
|
|
|
if ((generic.wm & XGWM_EWMH) != 0)
|
|
{
|
|
// Store the id of our process
|
|
Atom pid_atom = XInternAtom(dpy, "_NET_WM_PID", False);
|
|
int pid = [pInfo processIdentifier];
|
|
|
|
XChangeProperty(dpy, ROOT,
|
|
pid_atom, XA_CARDINAL,
|
|
32, PropModeReplace,
|
|
(unsigned char*)&pid, 1);
|
|
|
|
// We should store the GNUStepMenuImage in the root window
|
|
// and use that as our title bar icon
|
|
// pid_atom = XInternAtom(dpy, "_NET_WM_ICON", False);
|
|
}
|
|
}
|
|
|
|
/* Destroys all the windows and other window resources that belong to
|
|
this context */
|
|
- (void) _destroyServerWindows
|
|
{
|
|
int num;
|
|
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, (void**)&num, (void**)&d) == YES)
|
|
{
|
|
if (d->display == dpy && d->ident != d->root)
|
|
[self termwindow: num];
|
|
}
|
|
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
|
|
{
|
|
if (window->type == NSBackingStoreNonretained
|
|
|| (window->gdriverProtocol & GDriverHandlesBacking))
|
|
return;
|
|
|
|
if (window->depth == 0)
|
|
window->depth = DefaultDepth(dpy, window->screen);
|
|
if (NSWidth(window->xframe) == 0 && NSHeight(window->xframe) == 0)
|
|
{
|
|
NSDebugLLog(@"NSWindow", @"Cannot create buffer for ZeroRect frame");
|
|
return;
|
|
}
|
|
|
|
window->buffer = XCreatePixmap(dpy, window->root,
|
|
NSWidth(window->xframe),
|
|
NSHeight(window->xframe),
|
|
window->depth);
|
|
|
|
if (!window->buffer)
|
|
{
|
|
NSLog(@"DPS Windows: Unable to create backing store\n");
|
|
return;
|
|
}
|
|
|
|
XFillRectangle(dpy,
|
|
window->buffer,
|
|
window->gc,
|
|
0, 0,
|
|
NSWidth(window->xframe),
|
|
NSHeight(window->xframe));
|
|
}
|
|
|
|
- (int) window: (NSRect)frame : (NSBackingStoreType)type : (unsigned int)style
|
|
: (int)screen
|
|
{
|
|
static int last_win_num = 0;
|
|
gswindow_device_t *window;
|
|
gswindow_device_t *root;
|
|
XGCValues values;
|
|
unsigned long valuemask;
|
|
XClassHint classhint;
|
|
RContext *context;
|
|
|
|
NSDebugLLog(@"XGTrace", @"DPSwindow: %@ %d", NSStringFromRect(frame), type);
|
|
root = [self _rootWindowForScreen: screen];
|
|
context = [self xrContextForScreen: screen];
|
|
|
|
frame = [NSWindow contentRectForFrameRect: frame styleMask: style];
|
|
|
|
/* We're not allowed to create a zero rect window */
|
|
if (NSWidth(frame) <= 0 || NSHeight(frame) <= 0)
|
|
{
|
|
frame.size.width = 2;
|
|
frame.size.height = 2;
|
|
}
|
|
/* Translate to X coordinates */
|
|
frame.origin.y = DisplayHeight(dpy, screen) - NSMaxY(frame);
|
|
|
|
window = objc_malloc(sizeof(gswindow_device_t));
|
|
memset(window, '\0', sizeof(gswindow_device_t));
|
|
window->display = dpy;
|
|
window->screen = screen;
|
|
window->xframe = frame;
|
|
window->type = type;
|
|
window->root = root->ident;
|
|
window->parent = root->ident;
|
|
window->depth = context->depth;
|
|
window->xwn_attrs.border_pixel = context->black;
|
|
window->xwn_attrs.background_pixel = context->white;
|
|
window->xwn_attrs.colormap = context->cmap;
|
|
|
|
window->ident = XCreateWindow(dpy, window->root,
|
|
NSMinX(frame), NSMinY(frame),
|
|
NSWidth(frame), NSHeight(frame),
|
|
0,
|
|
context->depth,
|
|
CopyFromParent,
|
|
context->visual,
|
|
(CWColormap | CWBackPixel|CWBorderPixel),
|
|
&window->xwn_attrs);
|
|
|
|
/*
|
|
* Mark this as a GNUstep app with the current application name.
|
|
*/
|
|
classhint.res_name = rootName;
|
|
classhint.res_class = "GNUstep";
|
|
XSetClassHint(dpy, window->ident, &classhint);
|
|
|
|
window->xwn_attrs.save_under = False;
|
|
window->xwn_attrs.override_redirect = False;
|
|
window->map_state = IsUnmapped;
|
|
window->visibility = -1;
|
|
|
|
// Create an X GC for the content view set it's colors
|
|
values.foreground = window->xwn_attrs.background_pixel;
|
|
values.background = window->xwn_attrs.background_pixel;
|
|
values.function = GXcopy;
|
|
valuemask = (GCForeground | GCBackground | GCFunction);
|
|
window->gc = XCreateGC(dpy, window->ident, valuemask, &values);
|
|
|
|
// Set the X event mask
|
|
XSelectInput(dpy, window->ident, ExposureMask | KeyPressMask |
|
|
KeyReleaseMask | ButtonPressMask |
|
|
ButtonReleaseMask | ButtonMotionMask |
|
|
StructureNotifyMask | PointerMotionMask |
|
|
EnterWindowMask | LeaveWindowMask |
|
|
FocusChangeMask | PropertyChangeMask |
|
|
ColormapChangeMask | KeymapStateMask |
|
|
VisibilityChangeMask);
|
|
|
|
/*
|
|
* Initial attributes for any GNUstep window tell Window Maker not to
|
|
* create an app icon for us.
|
|
*/
|
|
window->win_attrs.flags = GSExtraFlagsAttr;
|
|
window->win_attrs.extra_flags = GSNoApplicationIconFlag;
|
|
|
|
/*
|
|
* Prepare size/position hints, but don't set them now - ordering
|
|
* the window in should automatically do it.
|
|
*/
|
|
window->win_attrs.flags |= GSWindowStyleAttr;
|
|
window->win_attrs.window_style = style;
|
|
frame = [self _XFrameToOSFrame: window->xframe for: window];
|
|
frame = [self _OSFrameToXHints: frame for: window];
|
|
window->siz_hints.x = NSMinX(frame);
|
|
window->siz_hints.y = NSMinY(frame);
|
|
window->siz_hints.width = NSWidth(frame);
|
|
window->siz_hints.height = NSHeight(frame);
|
|
window->siz_hints.flags = USPosition|PPosition|USSize|PSize;
|
|
|
|
// Always send GNUstepWMAttributes
|
|
XChangeProperty(dpy, window->ident, generic.win_decor_atom,
|
|
generic.win_decor_atom, 32, PropModeReplace,
|
|
(unsigned char *)&window->win_attrs,
|
|
sizeof(GNUstepWMAttributes)/sizeof(CARD32));
|
|
|
|
// send to the WM window style hints
|
|
if ((generic.wm & XGWM_WINDOWMAKER) == 0)
|
|
{
|
|
setWindowHintsForStyle (dpy, window->ident, style);
|
|
}
|
|
|
|
// Use the globally active input mode
|
|
window->gen_hints.flags = InputHint;
|
|
window->gen_hints.input = False;
|
|
// All the windows of a GNUstep application belong to one group.
|
|
window->gen_hints.flags |= WindowGroupHint;
|
|
window->gen_hints.window_group = ROOT;
|
|
|
|
/*
|
|
* Prepare the protocols supported by the window.
|
|
* These protocols should be set on the window when it is ordered in.
|
|
*/
|
|
window->numProtocols = 0;
|
|
window->protocols[window->numProtocols++] = generic.take_focus_atom;
|
|
window->protocols[window->numProtocols++] = generic.delete_win_atom;
|
|
if ((generic.wm & XGWM_WINDOWMAKER) != 0)
|
|
{
|
|
window->protocols[window->numProtocols++] = generic.miniaturize_atom;
|
|
}
|
|
// FIXME Add ping protocol for EWMH
|
|
XSetWMProtocols(dpy, window->ident, window->protocols, window->numProtocols);
|
|
|
|
window->exposedRects = [NSMutableArray new];
|
|
window->region = XCreateRegion();
|
|
window->buffer = 0;
|
|
window->alpha_buffer = 0;
|
|
window->ic = 0;
|
|
|
|
// make sure that new window has the correct cursor
|
|
[self _initializeCursorForXWindow: window->ident];
|
|
|
|
/*
|
|
* 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*)window->ident, window);
|
|
NSMapInsert(windowtags, (void*)window->number, window);
|
|
[self _setWindowOwnedByServer: window->number];
|
|
return window->number;
|
|
}
|
|
|
|
- (void) termwindow: (int)win
|
|
{
|
|
gswindow_device_t *window;
|
|
|
|
window = WINDOW_WITH_TAG(win);
|
|
if (!window)
|
|
return;
|
|
|
|
if (window->root == window->ident)
|
|
{
|
|
NSLog(@"DPStermwindow: Trying to destroy root window");
|
|
return;
|
|
}
|
|
|
|
NSDebugLLog(@"XGTrace", @"DPStermwindow: %d", win);
|
|
if (window->ic)
|
|
{
|
|
[inputServer ximCloseIC: window->ic];
|
|
}
|
|
if (window->ident)
|
|
{
|
|
XDestroyWindow(dpy, window->ident);
|
|
if (window->gc)
|
|
XFreeGC (dpy, window->gc);
|
|
NSMapRemove(windowmaps, (void*)window->ident);
|
|
}
|
|
|
|
if (window->buffer && (window->gdriverProtocol & GDriverHandlesBacking) == 0)
|
|
XFreePixmap (dpy, window->buffer);
|
|
if (window->alpha_buffer
|
|
&& (window->gdriverProtocol & GDriverHandlesBacking) == 0)
|
|
XFreePixmap (dpy, window->alpha_buffer);
|
|
if (window->region)
|
|
XDestroyRegion (window->region);
|
|
RELEASE(window->exposedRects);
|
|
NSMapRemove(windowtags, (void*)win);
|
|
objc_free(window);
|
|
}
|
|
|
|
/*
|
|
* 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
|
|
{
|
|
/* First try to get the offset information that we have obtained from
|
|
the WM. This will only work if the application has already created
|
|
a window that has been reparented by the WM. Otherwise we have to
|
|
guess.
|
|
*/
|
|
if (generic.parent_offset.x || generic.parent_offset.y)
|
|
{
|
|
if (style == NSBorderlessWindowMask
|
|
|| (style & NSIconWindowMask) || (style & NSMiniWindowMask))
|
|
{
|
|
*l = *r = *t = *b = 0.0;
|
|
}
|
|
else
|
|
{
|
|
*l = *r = *t = *b = generic.parent_offset.x;
|
|
if (NSResizableWindowMask & style)
|
|
{
|
|
/* We just have to guess this. Usually it doesn't matter */
|
|
if ((generic.wm & XGWM_WINDOWMAKER) != 0)
|
|
*b = 9;
|
|
else if ((generic.wm & XGWM_EWMH) != 0)
|
|
*b = 7;
|
|
}
|
|
if ((style & NSTitledWindowMask) || (style & NSClosableWindowMask)
|
|
|| (style & NSMiniaturizableWindowMask))
|
|
{
|
|
*t = generic.parent_offset.y;
|
|
}
|
|
}
|
|
}
|
|
else if ((generic.wm & XGWM_WINDOWMAKER) != 0)
|
|
{
|
|
if (style == NSBorderlessWindowMask
|
|
|| (style & NSIconWindowMask) || (style & NSMiniWindowMask))
|
|
{
|
|
*l = *r = *t = *b = 0.0;
|
|
}
|
|
else
|
|
{
|
|
*l = *r = *t = *b = 0;
|
|
if (NSResizableWindowMask & style)
|
|
{
|
|
*b = 9;
|
|
}
|
|
if ((style & NSTitledWindowMask) || (style & NSClosableWindowMask)
|
|
|| (style & NSMiniaturizableWindowMask))
|
|
{
|
|
*t = 22;
|
|
}
|
|
}
|
|
}
|
|
else if ((generic.wm & XGWM_EWMH) != 0)
|
|
{
|
|
if (style == NSBorderlessWindowMask
|
|
|| (style & NSIconWindowMask) || (style & NSMiniWindowMask))
|
|
{
|
|
*l = *r = *t = *b = 0.0;
|
|
}
|
|
else
|
|
{
|
|
*l = *r = *t = *b = 4;
|
|
if (NSResizableWindowMask & style)
|
|
{
|
|
*b = 7;
|
|
}
|
|
if ((style & NSTitledWindowMask) || (style & NSClosableWindowMask)
|
|
|| (style & NSMiniaturizableWindowMask))
|
|
{
|
|
*t = 20;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* No known WM protocols */
|
|
/*
|
|
* FIXME
|
|
* This should make a good guess - at the moment use no offsets.
|
|
*/
|
|
*l = *r = *t = *b = 0.0;
|
|
}
|
|
}
|
|
|
|
- (void) stylewindow: (unsigned int)style : (int) win
|
|
{
|
|
gswindow_device_t *window;
|
|
|
|
window = WINDOW_WITH_TAG(win);
|
|
if (!window)
|
|
return;
|
|
|
|
NSDebugLLog(@"XGTrace", @"DPSstylewindow: %d : %d", style, win);
|
|
if (window->win_attrs.window_style != style
|
|
|| (window->win_attrs.flags & GSWindowStyleAttr) == 0)
|
|
{
|
|
NSRect h;
|
|
window->win_attrs.flags |= GSWindowStyleAttr;
|
|
window->win_attrs.window_style = style;
|
|
|
|
/* Fix up hints */
|
|
h = [self _XFrameToOSFrame: window->xframe for: window];
|
|
h = [self _OSFrameToXHints: h for: window];
|
|
window->siz_hints.x = NSMinX(h);
|
|
window->siz_hints.y = NSMinY(h);
|
|
window->siz_hints.width = NSWidth(h);
|
|
window->siz_hints.height = NSHeight(h);
|
|
|
|
// send to the WM window style hints
|
|
XChangeProperty(dpy, window->ident, generic.win_decor_atom,
|
|
generic.win_decor_atom, 32, PropModeReplace,
|
|
(unsigned char *)&window->win_attrs,
|
|
sizeof(GNUstepWMAttributes)/sizeof(CARD32));
|
|
|
|
// send to the WM window style hints
|
|
if ((generic.wm & XGWM_WINDOWMAKER) == 0)
|
|
{
|
|
setWindowHintsForStyle (dpy, window->ident, style);
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void) setbackgroundcolor: (NSColor *)color : (int)win
|
|
{
|
|
XColor xf;
|
|
gswindow_device_t *window;
|
|
|
|
window = WINDOW_WITH_TAG(win);
|
|
if (!window)
|
|
return;
|
|
|
|
|
|
color = [color colorUsingColorSpaceName: NSDeviceRGBColorSpace];
|
|
xf.red = 65535 * [color redComponent];
|
|
xf.green = 65535 * [color greenComponent];
|
|
xf.blue = 65535 * [color blueComponent];
|
|
NSDebugLLog(@"XGTrace", @"setbackgroundcolor: %@ %d", color, win);
|
|
xf = [self xColorFromColor: xf forScreen: window->screen];
|
|
window->xwn_attrs.background_pixel = xf.pixel;
|
|
XSetWindowBackground(dpy, window->ident, window->xwn_attrs.background_pixel);
|
|
}
|
|
|
|
- (void) windowbacking: (NSBackingStoreType)type : (int) win
|
|
{
|
|
gswindow_device_t *window;
|
|
|
|
window = WINDOW_WITH_TAG(win);
|
|
if (!window)
|
|
return;
|
|
|
|
NSDebugLLog(@"XGTrace", @"DPSwindowbacking: %@ : %d", type, win);
|
|
|
|
if ((window->gdriverProtocol & GDriverHandlesBacking))
|
|
{
|
|
window->type = type;
|
|
return;
|
|
}
|
|
|
|
if (window->buffer && type == NSBackingStoreNonretained)
|
|
{
|
|
XFreePixmap (dpy, window->buffer);
|
|
window->buffer = 0;
|
|
}
|
|
window->type = type;
|
|
[self _createBuffer: window];
|
|
}
|
|
|
|
- (void) titlewindow: (NSString *)window_title : (int) win
|
|
{
|
|
XTextProperty windowName;
|
|
gswindow_device_t *window;
|
|
|
|
window = WINDOW_WITH_TAG(win);
|
|
if (!window)
|
|
return;
|
|
|
|
NSDebugLLog(@"XGTrace", @"DPStitlewindow: %@ : %d", window_title, win);
|
|
if (window_title && window->ident)
|
|
{
|
|
const char *title = [window_title lossyCString];
|
|
XStringListToTextProperty((char**)&title, 1, &windowName);
|
|
XSetWMName(dpy, window->ident, &windowName);
|
|
XSetWMIconName(dpy, window->ident, &windowName);
|
|
XFree(windowName.value);
|
|
}
|
|
}
|
|
|
|
- (void) docedited: (int)edited : (int) win
|
|
{
|
|
gswindow_device_t *window;
|
|
|
|
window = WINDOW_WITH_TAG(win);
|
|
if (!window)
|
|
return;
|
|
|
|
NSDebugLLog(@"XGTrace", @"DPSdocedited: %d : %d", edited, win);
|
|
window->win_attrs.flags |= GSExtraFlagsAttr;
|
|
if (edited)
|
|
{
|
|
window->win_attrs.extra_flags |= GSDocumentEditedFlag;
|
|
}
|
|
else
|
|
{
|
|
window->win_attrs.extra_flags &= ~GSDocumentEditedFlag;
|
|
}
|
|
|
|
// send WindowMaker WM window style hints
|
|
// Always send GNUstepWMAttributes
|
|
XChangeProperty(dpy, window->ident,
|
|
generic.win_decor_atom, generic.win_decor_atom,
|
|
32, PropModeReplace, (unsigned char *)&window->win_attrs,
|
|
sizeof(GNUstepWMAttributes)/sizeof(CARD32));
|
|
}
|
|
|
|
- (BOOL) appOwnsMiniwindow
|
|
{
|
|
return generic.flags.appOwnsMiniwindow;
|
|
}
|
|
|
|
- (void) miniwindow: (int) win
|
|
{
|
|
gswindow_device_t *window;
|
|
|
|
window = WINDOW_WITH_TAG(win);
|
|
if (window == 0 || (window->win_attrs.window_style & NSIconWindowMask) != 0)
|
|
{
|
|
return;
|
|
}
|
|
NSDebugLLog(@"XGTrace", @"DPSminiwindow: %d ", win);
|
|
/*
|
|
* If we haven't already done so - set the icon window hint for this
|
|
* window so that the GNUstep miniwindow is displayed (if supported).
|
|
*/
|
|
if (generic.flags.appOwnsMiniwindow
|
|
&& (window->gen_hints.flags & IconWindowHint) == 0)
|
|
{
|
|
NSWindow *nswin;
|
|
|
|
nswin = GSWindowWithNumber(window->number);
|
|
if (nswin != nil)
|
|
{
|
|
int iNum = [[nswin counterpart] windowNumber];
|
|
gswindow_device_t *iconw = WINDOW_WITH_TAG(iNum);
|
|
|
|
if (iconw != 0)
|
|
{
|
|
window->gen_hints.flags |= IconWindowHint;
|
|
window->gen_hints.icon_window = iconw->ident;
|
|
XSetWMHints(dpy, window->ident, &window->gen_hints);
|
|
}
|
|
}
|
|
}
|
|
XIconifyWindow(dpy, window->ident, window->screen);
|
|
}
|
|
|
|
/**
|
|
Make sure we have the most up-to-date window information and then
|
|
make sure the current context has our new information
|
|
*/
|
|
- (void) windowdevice: (int)win
|
|
{
|
|
int x, y;
|
|
unsigned width, height;
|
|
unsigned old_width;
|
|
unsigned old_height;
|
|
XWindowAttributes winattr;
|
|
gswindow_device_t *window;
|
|
NSGraphicsContext *ctxt;
|
|
|
|
NSDebugLLog(@"XGTrace", @"DPSwindowdevice: %d ", win);
|
|
window = WINDOW_WITH_TAG(win);
|
|
if (!window)
|
|
{
|
|
NSLog(@"Invalidparam: Invalid window number %d", win);
|
|
return;
|
|
}
|
|
|
|
if (!window->ident)
|
|
return;
|
|
|
|
old_width = NSWidth(window->xframe);
|
|
old_height = NSHeight(window->xframe);
|
|
|
|
XFlush (dpy);
|
|
|
|
XGetGeometry(dpy, window->ident, &window->root,
|
|
&x, &y, &width, &height,
|
|
&window->border, &window->depth);
|
|
/* hack:
|
|
* wait until a resize of window is finished (especially for NSMenu)
|
|
* is there any way to wait until X finished it's stuff?
|
|
* XSync(), XFlush() doesn't do the job!
|
|
*/
|
|
if (height != (unsigned int)(window->siz_hints.height))
|
|
{
|
|
#if HAVE_USLEEP
|
|
usleep(1);
|
|
#else
|
|
for (x=0; x<10000; x++)
|
|
;
|
|
#endif
|
|
XGetGeometry(dpy, window->ident, &window->root,
|
|
&x, &y, &width, &height,
|
|
&window->border, &window->depth);
|
|
}
|
|
|
|
window->xframe.size.width = width;
|
|
window->xframe.size.height = height;
|
|
|
|
XGetWindowAttributes(dpy, window->ident, &winattr);
|
|
window->map_state = winattr.map_state;
|
|
|
|
NSDebugLLog (@"NSWindow", @"window geom device ((%f, %f), (%f, %f))",
|
|
window->xframe.origin.x, window->xframe.origin.y,
|
|
window->xframe.size.width, window->xframe.size.height);
|
|
|
|
if (window->buffer && (old_width != width || old_height != height)
|
|
&& (window->gdriverProtocol & GDriverHandlesBacking) == 0)
|
|
{
|
|
[isa waitAllContexts];
|
|
XFreePixmap(dpy, window->buffer);
|
|
window->buffer = 0;
|
|
if (window->alpha_buffer)
|
|
XFreePixmap (dpy, window->alpha_buffer);
|
|
window->alpha_buffer = 0;
|
|
}
|
|
|
|
if (window->buffer == 0)
|
|
{
|
|
[self _createBuffer: window];
|
|
}
|
|
|
|
ctxt = GSCurrentContext();
|
|
GSSetDevice(ctxt, window, 0, NSHeight(window->xframe));
|
|
DPSinitmatrix(ctxt);
|
|
DPSinitclip(ctxt);
|
|
}
|
|
|
|
- (void) orderwindow: (int)op : (int)otherWin : (int)winNum
|
|
{
|
|
gswindow_device_t *window;
|
|
gswindow_device_t *other;
|
|
int level;
|
|
|
|
window = WINDOW_WITH_TAG(winNum);
|
|
if (winNum == 0 || window == NULL)
|
|
{
|
|
NSLog(@"Invalidparam: Ordering invalid window %d", winNum);
|
|
return;
|
|
}
|
|
|
|
if (op != NSWindowOut)
|
|
{
|
|
/*
|
|
* Some window managers ignore any hints and properties until the
|
|
* window is actually mapped, so we need to set them all up
|
|
* immediately bofore mapping the window ...
|
|
*/
|
|
|
|
setNormalHints(dpy, window);
|
|
XSetWMHints(dpy, window->ident, &window->gen_hints);
|
|
|
|
/*
|
|
* If we are asked to set hints for the appicon and Window Maker is
|
|
* to control it, we must let Window maker know that this window is
|
|
* the icon window for the app root window.
|
|
*/
|
|
if ((window->win_attrs.window_style & NSIconWindowMask) != 0
|
|
&& generic.flags.useWindowMakerIcons == 1)
|
|
{
|
|
XWMHints gen_hints;
|
|
|
|
gen_hints.flags = WindowGroupHint | StateHint | IconWindowHint;
|
|
gen_hints.initial_state = WithdrawnState;
|
|
gen_hints.window_group = ROOT;
|
|
gen_hints.icon_window = window->ident;
|
|
XSetWMHints(dpy, ROOT, &gen_hints);
|
|
}
|
|
|
|
/*
|
|
* Tell the window manager what protocols this window conforms to.
|
|
*/
|
|
XSetWMProtocols(dpy, window->ident, window->protocols,
|
|
window->numProtocols);
|
|
}
|
|
|
|
if (generic.flags.useWindowMakerIcons == 1)
|
|
{
|
|
/*
|
|
* Icon windows are mapped/unmapped by the window manager - so we
|
|
* mustn't do anything with them here - though we can raise the
|
|
* application root window to let Window Maker know it should use
|
|
* our appicon window.
|
|
*/
|
|
if ((window->win_attrs.window_style & NSIconWindowMask) != 0)
|
|
{
|
|
if (op != NSWindowOut)
|
|
{
|
|
XMapRaised(dpy, ROOT);
|
|
}
|
|
return;
|
|
}
|
|
if ((window->win_attrs.window_style & NSMiniWindowMask) != 0)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
NSDebugLLog(@"XGTrace", @"DPSorderwindow: %d : %d : %d",op,otherWin,winNum);
|
|
level = window->win_attrs.window_level;
|
|
if (otherWin > 0)
|
|
{
|
|
other = WINDOW_WITH_TAG(otherWin);
|
|
if (other)
|
|
level = other->win_attrs.window_level;
|
|
}
|
|
else if (otherWin == 0 && op == NSWindowAbove)
|
|
{
|
|
/* Don't let the window go in front of the current key/main window. */
|
|
/* FIXME: Don't know how to get the current main window. */
|
|
Window keywin;
|
|
int revert, status;
|
|
status = XGetInputFocus(dpy, &keywin, &revert);
|
|
other = NULL;
|
|
if (status == True)
|
|
{
|
|
/* Alloc a temporary window structure */
|
|
other = GSAutoreleasedBuffer(sizeof(gswindow_device_t));
|
|
other->ident = keywin;
|
|
op = NSWindowBelow;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
other = NULL;
|
|
}
|
|
[self setwindowlevel: level : winNum];
|
|
|
|
/*
|
|
* When we are ordering a window in, we must ensure that the position
|
|
* and size hints are set for the window - the window could have been
|
|
* moved or resized by the window manager before it was ordered out,
|
|
* in which case, we will have been notified of the new position, but
|
|
* will not yet have updated the window hints, so if the window manager
|
|
* looks at the existing hints when re-mapping the window it will
|
|
* place the window in an old location.
|
|
* We also set other hints and protocols supported by the window.
|
|
*/
|
|
if (op != NSWindowOut && window->map_state != IsViewable)
|
|
{
|
|
XMoveWindow(dpy, window->ident, window->siz_hints.x,
|
|
window->siz_hints.y);
|
|
setNormalHints(dpy, window);
|
|
/* Set this to ignore any take focus events for this window */
|
|
generic.desiredOrderedWindow = winNum;
|
|
}
|
|
|
|
switch (op)
|
|
{
|
|
case NSWindowBelow:
|
|
if (other != 0)
|
|
{
|
|
XWindowChanges chg;
|
|
chg.sibling = other->ident;
|
|
chg.stack_mode = Below;
|
|
XReconfigureWMWindow(dpy, window->ident, window->screen,
|
|
CWSibling|CWStackMode, &chg);
|
|
}
|
|
else
|
|
{
|
|
XWindowChanges chg;
|
|
chg.stack_mode = Below;
|
|
XReconfigureWMWindow(dpy, window->ident, window->screen,
|
|
CWStackMode, &chg);
|
|
}
|
|
XMapWindow(dpy, window->ident);
|
|
break;
|
|
|
|
case NSWindowAbove:
|
|
if (other != 0)
|
|
{
|
|
XWindowChanges chg;
|
|
chg.sibling = other->ident;
|
|
chg.stack_mode = Above;
|
|
XReconfigureWMWindow(dpy, window->ident, window->screen,
|
|
CWSibling|CWStackMode, &chg);
|
|
}
|
|
else
|
|
{
|
|
XWindowChanges chg;
|
|
chg.stack_mode = Above;
|
|
XReconfigureWMWindow(dpy, window->ident, window->screen,
|
|
CWStackMode, &chg);
|
|
}
|
|
XMapWindow(dpy, window->ident);
|
|
break;
|
|
|
|
case NSWindowOut:
|
|
XWithdrawWindow (dpy, window->ident, window->screen);
|
|
break;
|
|
}
|
|
/*
|
|
* When we are ordering a window in, we must ensure that the position
|
|
* and size hints are set for the window - the window could have been
|
|
* moved or resized by the window manager before it was ordered out,
|
|
* in which case, we will have been notified of the new position, but
|
|
* will not yet have updated the window hints, so if the window manager
|
|
* looks at the existing hints when re-mapping the window it will
|
|
* place the window in an old location.
|
|
*/
|
|
if (op != NSWindowOut && window->map_state != IsViewable)
|
|
{
|
|
XMoveWindow(dpy, window->ident, window->siz_hints.x,
|
|
window->siz_hints.y);
|
|
setNormalHints(dpy, window);
|
|
/*
|
|
* Do we need to setup drag types when the window is mapped or will
|
|
* they work on the set up before mapping?
|
|
*
|
|
* [self _resetDragTypesForWindow: GSWindowWithNumber(window->number)];
|
|
*/
|
|
}
|
|
XFlush(dpy);
|
|
}
|
|
|
|
#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
|
|
{
|
|
gswindow_device_t *window;
|
|
Pixmap pixmap = 0;
|
|
|
|
window = WINDOW_WITH_TAG(win);
|
|
if (win == 0 || window == NULL)
|
|
{
|
|
NSLog(@"Invalidparam: Restricting invalid window %d", win);
|
|
return;
|
|
}
|
|
|
|
if ([[image backgroundColor] alphaComponent] * 256 <= ALPHA_THRESHOLD)
|
|
{
|
|
// The mask computed here is only correct for unscaled images.
|
|
NSImageRep *rep = [image bestRepresentationForDevice: nil];
|
|
|
|
if ([rep isKindOfClass: [NSBitmapImageRep class]])
|
|
{
|
|
if (![(NSBitmapImageRep*)rep isPlanar] &&
|
|
([(NSBitmapImageRep*)rep samplesPerPixel] == 4))
|
|
{
|
|
pixmap = xgps_cursor_mask(dpy, GET_XDRAWABLE(window),
|
|
[(NSBitmapImageRep*)rep bitmapData],
|
|
[rep pixelsWide], [rep pixelsHigh],
|
|
[(NSBitmapImageRep*)rep samplesPerPixel]);
|
|
}
|
|
}
|
|
}
|
|
|
|
XShapeCombineMask(dpy, window->ident, ShapeBounding, 0, 0,
|
|
pixmap, ShapeSet);
|
|
|
|
if (pixmap)
|
|
{
|
|
XFreePixmap(dpy, pixmap);
|
|
}
|
|
}
|
|
|
|
/* This method is a fast implementation of move that only works
|
|
correctly for borderless windows. Use with caution. */
|
|
- (void) movewindow: (NSPoint)loc : (int)win
|
|
{
|
|
gswindow_device_t *window;
|
|
|
|
window = WINDOW_WITH_TAG(win);
|
|
if (win == 0 || window == NULL)
|
|
{
|
|
NSLog(@"Invalidparam: Moving invalid window %d", win);
|
|
return;
|
|
}
|
|
|
|
window->siz_hints.x = (int)loc.x;
|
|
window->siz_hints.y = (int)(DisplayHeight(dpy, window->screen) -
|
|
loc.y - window->siz_hints.height);
|
|
XMoveWindow (dpy, window->ident, window->siz_hints.x, window->siz_hints.y);
|
|
setNormalHints(dpy, window);
|
|
}
|
|
|
|
- (void) placewindow: (NSRect)rect : (int)win
|
|
{
|
|
NSAutoreleasePool *arp;
|
|
NSRect xVal;
|
|
NSRect last;
|
|
NSEvent *event;
|
|
NSDate *limit;
|
|
NSMutableArray *tmpQueue;
|
|
unsigned pos;
|
|
float xdiff;
|
|
float ydiff;
|
|
gswindow_device_t *window;
|
|
NSWindow *nswin;
|
|
NSRect frame;
|
|
BOOL resize = NO;
|
|
BOOL move = NO;
|
|
|
|
window = WINDOW_WITH_TAG(win);
|
|
if (win == 0 || window == NULL)
|
|
{
|
|
NSLog(@"Invalidparam: Placing invalid window %d", win);
|
|
return;
|
|
}
|
|
|
|
NSDebugLLog(@"XGTrace", @"DPSplacewindow: %@ : %d", NSStringFromRect(rect),
|
|
win);
|
|
nswin = GSWindowWithNumber(win);
|
|
frame = [nswin frame];
|
|
if (NSEqualRects(rect, frame) == YES)
|
|
return;
|
|
if (NSEqualSizes(rect.size, frame.size) == NO)
|
|
{
|
|
resize = YES;
|
|
move = YES;
|
|
}
|
|
if (NSEqualPoints(rect.origin, frame.origin) == NO)
|
|
{
|
|
move = YES;
|
|
}
|
|
xdiff = rect.origin.x - frame.origin.x;
|
|
ydiff = rect.origin.y - frame.origin.y;
|
|
|
|
xVal = [self _OSFrameToXHints: rect for: window];
|
|
window->siz_hints.width = (int)xVal.size.width;
|
|
window->siz_hints.height = (int)xVal.size.height;
|
|
window->siz_hints.x = (int)xVal.origin.x;
|
|
window->siz_hints.y = (int)xVal.origin.y;
|
|
xVal = [self _OSFrameToXFrame: rect for: window];
|
|
|
|
last = window->xframe;
|
|
|
|
NSDebugLLog(@"Moving", @"Place %d - o:%@, x:%@", window->number,
|
|
NSStringFromRect(rect), NSStringFromRect(xVal));
|
|
XMoveResizeWindow (dpy, window->ident,
|
|
window->siz_hints.x, window->siz_hints.y,
|
|
window->siz_hints.width, window->siz_hints.height);
|
|
setNormalHints(dpy, window);
|
|
|
|
/*
|
|
* Now massage all the events currently in the queue to make sure
|
|
* mouse locations in our window are adjusted as necessary.
|
|
*/
|
|
arp = [NSAutoreleasePool new];
|
|
limit = [NSDate distantPast]; /* Don't wait for new events. */
|
|
tmpQueue = [NSMutableArray arrayWithCapacity: 8];
|
|
for (;;)
|
|
{
|
|
NSEventType type;
|
|
|
|
event = DPSGetEvent(self, NSAnyEventMask, limit,
|
|
NSEventTrackingRunLoopMode);
|
|
if (event == nil)
|
|
break;
|
|
type = [event type];
|
|
if (type == NSAppKitDefined && [event windowNumber] == win)
|
|
{
|
|
GSAppKitSubtype sub = [event subtype];
|
|
|
|
/*
|
|
* Window movement or resize events for the window we are
|
|
* watching are posted immediately, so they can take effect
|
|
* before the placewindow returns.
|
|
*/
|
|
if (sub == GSAppKitWindowMoved || sub == GSAppKitWindowResized)
|
|
{
|
|
[nswin sendEvent: event];
|
|
}
|
|
else
|
|
{
|
|
[tmpQueue addObject: event];
|
|
}
|
|
}
|
|
else if (type != NSPeriodic && type != NSLeftMouseDragged
|
|
&& type != NSOtherMouseDragged && type != NSRightMouseDragged
|
|
&& type != NSMouseMoved)
|
|
{
|
|
/*
|
|
* Save any events that arrive before our window is moved - excepting
|
|
* periodic events (which we can assume will be outdated) and mouse
|
|
* movement events (which might flood us).
|
|
*/
|
|
[tmpQueue addObject: event];
|
|
}
|
|
if (NSEqualRects(xVal, window->xframe) == YES ||
|
|
NSEqualRects(rect, [nswin frame]) == YES)
|
|
{
|
|
break;
|
|
}
|
|
if (NSEqualRects(last, window->xframe) == NO)
|
|
{
|
|
NSDebugLLog(@"Moving", @"From: %@\nWant %@\nGot %@",
|
|
NSStringFromRect(last),
|
|
NSStringFromRect(xVal),
|
|
NSStringFromRect(window->xframe));
|
|
last = window->xframe;
|
|
}
|
|
}
|
|
/*
|
|
* If we got any events while waiting for the window movement, we
|
|
* may need to adjust their locations to match the new window position.
|
|
*/
|
|
pos = [tmpQueue count];
|
|
while (pos-- > 0)
|
|
{
|
|
event = [tmpQueue objectAtIndex: pos];
|
|
if ([event windowNumber] == win)
|
|
{
|
|
NSPoint loc = [event locationInWindow];
|
|
|
|
loc.x -= xdiff;
|
|
loc.y -= ydiff;
|
|
[event _patchLocation: loc];
|
|
}
|
|
DPSPostEvent(self, event, YES);
|
|
}
|
|
RELEASE(arp);
|
|
|
|
/*
|
|
* Failsafe - if X hasn't told us it has moved/resized the window, we
|
|
* fake the notification and post them immediately, so they can take
|
|
* effect before the placewindow returns.
|
|
*/
|
|
if (NSEqualRects([nswin frame], rect) == NO)
|
|
{
|
|
NSEvent *e;
|
|
|
|
if (resize == YES)
|
|
{
|
|
NSDebugLLog(@"Moving", @"Fake size %d - %@", window->number,
|
|
NSStringFromSize(rect.size));
|
|
e = [NSEvent otherEventWithType: NSAppKitDefined
|
|
location: rect.origin
|
|
modifierFlags: 0
|
|
timestamp: 0
|
|
windowNumber: win
|
|
context: GSCurrentContext()
|
|
subtype: GSAppKitWindowResized
|
|
data1: rect.size.width
|
|
data2: rect.size.height];
|
|
[nswin sendEvent: e];
|
|
}
|
|
if (move == YES)
|
|
{
|
|
NSDebugLLog(@"Moving", @"Fake move %d - %@", window->number,
|
|
NSStringFromPoint(rect.origin));
|
|
e = [NSEvent otherEventWithType: NSAppKitDefined
|
|
location: NSZeroPoint
|
|
modifierFlags: 0
|
|
timestamp: 0
|
|
windowNumber: win
|
|
context: GSCurrentContext()
|
|
subtype: GSAppKitWindowMoved
|
|
data1: rect.origin.x
|
|
data2: rect.origin.y];
|
|
[nswin sendEvent: e];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (BOOL) findwindow: (NSPoint)loc : (int) op : (int) otherWin : (NSPoint *)floc
|
|
: (int*) winFound
|
|
{
|
|
return NO;
|
|
}
|
|
|
|
- (NSRect) windowbounds: (int)win
|
|
{
|
|
gswindow_device_t *window;
|
|
int screenHeight;
|
|
NSRect rect;
|
|
|
|
window = WINDOW_WITH_TAG(win);
|
|
if (!window)
|
|
return NSZeroRect;
|
|
|
|
NSDebugLLog(@"XGTrace", @"DPScurrentwindowbounds: %d", win);
|
|
screenHeight = DisplayHeight(dpy, window->screen);
|
|
rect = window->xframe;
|
|
rect.origin.y = screenHeight - NSMaxY(window->xframe);
|
|
return rect;
|
|
}
|
|
|
|
- (void) setwindowlevel: (int)level : (int)win
|
|
{
|
|
gswindow_device_t *window;
|
|
|
|
window = WINDOW_WITH_TAG(win);
|
|
if (!window)
|
|
return;
|
|
|
|
NSDebugLLog(@"XGTrace", @"DPSsetwindowlevel: %d : %d", level, win);
|
|
if ((int)(window->win_attrs.window_level) != level
|
|
|| (window->win_attrs.flags & GSWindowLevelAttr) == 0)
|
|
{
|
|
window->win_attrs.flags |= GSWindowLevelAttr;
|
|
window->win_attrs.window_level = level;
|
|
|
|
// send WindowMaker WM window style hints
|
|
// Always send GNUstepWMAttributes
|
|
{
|
|
XEvent event;
|
|
|
|
/*
|
|
* First change the window properties so that, if the window
|
|
* is not mapped, we have stored the required info for when
|
|
* the WM maps it.
|
|
*/
|
|
XChangeProperty(dpy, window->ident,
|
|
generic.win_decor_atom, generic.win_decor_atom,
|
|
32, PropModeReplace, (unsigned char *)&window->win_attrs,
|
|
sizeof(GNUstepWMAttributes)/sizeof(CARD32));
|
|
/*
|
|
* Now send a message for rapid handling.
|
|
*/
|
|
event.xclient.type = ClientMessage;
|
|
event.xclient.message_type = generic.win_decor_atom;
|
|
event.xclient.format = 32;
|
|
event.xclient.display = dpy;
|
|
event.xclient.window = window->ident;
|
|
event.xclient.data.l[0] = GSWindowLevelAttr;
|
|
event.xclient.data.l[1] = window->win_attrs.window_level;
|
|
event.xclient.data.l[2] = 0;
|
|
event.xclient.data.l[3] = 0;
|
|
XSendEvent(dpy, DefaultRootWindow(dpy), False,
|
|
SubstructureRedirectMask, &event);
|
|
}
|
|
|
|
if ((generic.wm & XGWM_EWMH) != 0)
|
|
{
|
|
int len;
|
|
long data[2];
|
|
|
|
data[0] = generic.wintypes.win_normal_atom;
|
|
data[1] = None;
|
|
len = 1;
|
|
|
|
if (level == NSModalPanelWindowLevel)
|
|
{
|
|
data[0] = generic.wintypes.win_modal_atom;
|
|
}
|
|
else if (level == NSMainMenuWindowLevel)
|
|
{
|
|
// For strange reasons menu level does not work out for the main menu
|
|
//data[0] = generic.wintypes.win_topmenu_atom;
|
|
data[0] = generic.wintypes.win_dock_atom;
|
|
//len = 2;
|
|
}
|
|
else if (level == NSSubmenuWindowLevel ||
|
|
level == NSFloatingWindowLevel ||
|
|
level == NSTornOffMenuWindowLevel)
|
|
{
|
|
data[0] = generic.wintypes.win_override_atom;
|
|
//data[0] = generic.wintypes.win_utility_atom;
|
|
data[1] = generic.wintypes.win_menu_atom;
|
|
len = 2;
|
|
}
|
|
else if (level == NSDockWindowLevel ||
|
|
level == NSStatusWindowLevel)
|
|
{
|
|
data[0] =generic.wintypes.win_dock_atom;
|
|
}
|
|
// Does this belong into a different category?
|
|
else if (level == NSPopUpMenuWindowLevel)
|
|
{
|
|
data[0] = generic.wintypes.win_override_atom;
|
|
data[1] = generic.wintypes.win_floating_atom;
|
|
len = 2;
|
|
}
|
|
else if (level == NSDesktopWindowLevel)
|
|
{
|
|
data[0] = generic.wintypes.win_desktop_atom;
|
|
}
|
|
|
|
XChangeProperty(dpy, window->ident, generic.wintypes.win_type_atom,
|
|
XA_ATOM, 32, PropModeReplace,
|
|
(unsigned char *)&data, len);
|
|
}
|
|
else if ((generic.wm & XGWM_GNOME) != 0)
|
|
{
|
|
XEvent event;
|
|
int flag = WIN_LAYER_NORMAL;
|
|
|
|
if (level == NSDesktopWindowLevel)
|
|
flag = WIN_LAYER_DESKTOP;
|
|
else if (level == NSSubmenuWindowLevel
|
|
|| level == NSFloatingWindowLevel
|
|
|| level == NSTornOffMenuWindowLevel)
|
|
flag = WIN_LAYER_ONTOP;
|
|
else if (level == NSMainMenuWindowLevel)
|
|
flag = WIN_LAYER_MENU;
|
|
else if (level == NSDockWindowLevel
|
|
|| level == NSStatusWindowLevel)
|
|
flag = WIN_LAYER_DOCK;
|
|
else if (level == NSModalPanelWindowLevel
|
|
|| level == NSPopUpMenuWindowLevel)
|
|
flag = WIN_LAYER_ONTOP;
|
|
else if (level == NSScreenSaverWindowLevel)
|
|
flag = WIN_LAYER_ABOVE_DOCK;
|
|
|
|
XChangeProperty(dpy, window->ident, generic.wintypes.win_type_atom,
|
|
XA_CARDINAL, 32, PropModeReplace,
|
|
(unsigned char *)&flag, 1);
|
|
|
|
event.xclient.type = ClientMessage;
|
|
event.xclient.window = window->ident;
|
|
event.xclient.display = dpy;
|
|
event.xclient.message_type = generic.wintypes.win_type_atom;
|
|
event.xclient.format = 32;
|
|
event.xclient.data.l[0] = flag;
|
|
XSendEvent(dpy, window->root, False,
|
|
SubstructureNotifyMask, &event);
|
|
}
|
|
}
|
|
}
|
|
|
|
- (int) windowlevel: (int)win
|
|
{
|
|
gswindow_device_t *window;
|
|
|
|
window = WINDOW_WITH_TAG(win);
|
|
/*
|
|
* If we have previously set a level for this window - return the value set.
|
|
*/
|
|
if (window != 0 && (window->win_attrs.flags & GSWindowLevelAttr))
|
|
return window->win_attrs.window_level;
|
|
return 0;
|
|
}
|
|
|
|
- (NSArray *) windowlist
|
|
{
|
|
return nil;
|
|
}
|
|
|
|
- (int) windowdepth: (int)win
|
|
{
|
|
gswindow_device_t *window;
|
|
|
|
window = WINDOW_WITH_TAG(win);
|
|
if (!window)
|
|
return 0;
|
|
|
|
return window->depth;
|
|
}
|
|
|
|
- (void) setmaxsize: (NSSize)size : (int)win
|
|
{
|
|
gswindow_device_t *window;
|
|
NSRect r;
|
|
|
|
window = WINDOW_WITH_TAG(win);
|
|
if (window == 0)
|
|
{
|
|
return;
|
|
}
|
|
r = NSMakeRect(0, 0, size.width, size.height);
|
|
r = [self _OSFrameToXFrame: r for: window];
|
|
window->siz_hints.flags |= PMaxSize;
|
|
window->siz_hints.max_width = r.size.width;
|
|
window->siz_hints.max_height = r.size.height;
|
|
setNormalHints(dpy, window);
|
|
}
|
|
|
|
- (void) setminsize: (NSSize)size : (int)win
|
|
{
|
|
gswindow_device_t *window;
|
|
NSRect r;
|
|
|
|
window = WINDOW_WITH_TAG(win);
|
|
if (window == 0)
|
|
{
|
|
return;
|
|
}
|
|
r = NSMakeRect(0, 0, size.width, size.height);
|
|
r = [self _OSFrameToXFrame: r for: window];
|
|
window->siz_hints.flags |= PMinSize;
|
|
window->siz_hints.min_width = r.size.width;
|
|
window->siz_hints.min_height = r.size.height;
|
|
setNormalHints(dpy, window);
|
|
}
|
|
|
|
- (void) setresizeincrements: (NSSize)size : (int)win
|
|
{
|
|
gswindow_device_t *window;
|
|
|
|
window = WINDOW_WITH_TAG(win);
|
|
if (window == 0)
|
|
{
|
|
return;
|
|
}
|
|
window->siz_hints.flags |= PResizeInc;
|
|
window->siz_hints.width_inc = size.width;
|
|
window->siz_hints.height_inc = size.height;
|
|
setNormalHints(dpy, window);
|
|
}
|
|
|
|
// process expose event
|
|
- (void) _addExposedRectangle: (XRectangle)rectangle : (int)win
|
|
{
|
|
gswindow_device_t *window;
|
|
|
|
window = WINDOW_WITH_TAG(win);
|
|
if (!window)
|
|
return;
|
|
|
|
if (window->type != NSBackingStoreNonretained)
|
|
{
|
|
XGCValues values;
|
|
unsigned long valuemask;
|
|
|
|
// window has a backing store so just copy the exposed rect from the
|
|
// pixmap to the X window
|
|
|
|
NSDebugLLog (@"NSWindow", @"copy exposed area ((%d, %d), (%d, %d))",
|
|
rectangle.x, rectangle.y, rectangle.width, rectangle.height);
|
|
|
|
values.function = GXcopy;
|
|
values.plane_mask = AllPlanes;
|
|
values.clip_mask = None;
|
|
values.foreground = window->xwn_attrs.background_pixel;
|
|
valuemask = (GCFunction | GCPlaneMask | GCClipMask | GCForeground);
|
|
XChangeGC(dpy, window->gc, valuemask, &values);
|
|
[isa waitAllContexts];
|
|
if ((window->gdriverProtocol & GDriverHandlesExpose))
|
|
{
|
|
/* Temporary protocol until we standardize the backing buffer */
|
|
NSRect rect = NSMakeRect(rectangle.x, rectangle.y,
|
|
rectangle.width, rectangle.height);
|
|
[[GSCurrentContext() class] handleExposeRect: rect
|
|
forDriver: window->gdriver];
|
|
}
|
|
else
|
|
XCopyArea (dpy, window->buffer, window->ident, window->gc,
|
|
rectangle.x, rectangle.y, rectangle.width, rectangle.height,
|
|
rectangle.x, rectangle.y);
|
|
}
|
|
else
|
|
{
|
|
NSRect rect;
|
|
|
|
// no backing store, so keep a list of exposed rects to be
|
|
// processed in the _processExposedRectangles method
|
|
// Add the rectangle to the region used in -_processExposedRectangles
|
|
// to set the clipping path.
|
|
XUnionRectWithRegion (&rectangle, window->region, window->region);
|
|
|
|
// Transform the rectangle's coordinates to PS coordinates and add
|
|
// this new rectangle to the list of exposed rectangles.
|
|
{
|
|
rect = [self _XWinFrameToOSWinFrame:
|
|
NSMakeRect(rectangle.x, rectangle.y,
|
|
rectangle.width, rectangle.height)
|
|
for: window];
|
|
[window->exposedRects addObject: [NSValue valueWithRect: rect]];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void) flushwindowrect: (NSRect)rect : (int)win
|
|
{
|
|
int xi, yi, width, height;
|
|
XGCValues values;
|
|
unsigned long valuemask;
|
|
gswindow_device_t *window;
|
|
|
|
window = WINDOW_WITH_TAG(win);
|
|
if (win == 0 || window == NULL)
|
|
{
|
|
NSLog(@"Invalidparam: Placing invalid window %d", win);
|
|
return;
|
|
}
|
|
|
|
NSDebugLLog(@"XGTrace", @"DPSflushwindowrect: %@ : %d",
|
|
NSStringFromRect(rect), win);
|
|
if (window->type == NSBackingStoreNonretained)
|
|
{
|
|
XFlush(dpy);
|
|
return;
|
|
}
|
|
|
|
/* FIXME: Doesn't take into account any offset added to the window
|
|
(from PSsetgcdrawable) or possible scaling (unlikely in X-windows,
|
|
but what about other devices?) */
|
|
rect.origin.y = NSHeight(window->xframe) - NSMaxY(rect);
|
|
|
|
values.function = GXcopy;
|
|
values.plane_mask = AllPlanes;
|
|
values.clip_mask = None;
|
|
valuemask = (GCFunction | GCPlaneMask | GCClipMask);
|
|
XChangeGC(dpy, window->gc, valuemask, &values);
|
|
|
|
xi = NSMinX(rect); // width/height seems
|
|
yi = NSMinY(rect); // to require +1 pixel
|
|
width = NSWidth(rect) + 1; // to copy out
|
|
height = NSHeight(rect) + 1;
|
|
|
|
NSDebugLLog (@"NSWindow",
|
|
@"copy X rect ((%d, %d), (%d, %d))", xi, yi, width, height);
|
|
|
|
if (width > 0 || height > 0)
|
|
{
|
|
[isa waitAllContexts];
|
|
if ((window->gdriverProtocol & GDriverHandlesBacking))
|
|
{
|
|
/* Temporary protocol until we standardize the backing buffer */
|
|
[[GSCurrentContext() class] handleExposeRect: rect
|
|
forDriver: window->gdriver];
|
|
}
|
|
else
|
|
XCopyArea (dpy, window->buffer, window->ident, window->gc,
|
|
xi, yi, width, height, xi, yi);
|
|
}
|
|
|
|
XFlush(dpy);
|
|
}
|
|
|
|
// handle X expose events
|
|
- (void) _processExposedRectangles: (int)win
|
|
{
|
|
int n;
|
|
gswindow_device_t *window;
|
|
NSWindow *gui_win;
|
|
|
|
window = WINDOW_WITH_TAG(win);
|
|
if (!window)
|
|
return;
|
|
|
|
if (window->type != NSBackingStoreNonretained)
|
|
return;
|
|
|
|
// Set the clipping path to the exposed rectangles
|
|
// so that further drawing will not affect the non-exposed region
|
|
XSetRegion (dpy, window->gc, window->region);
|
|
|
|
// We should determine the views that need to be redisplayed. Until we
|
|
// fully support scalation and rotation of views redisplay everything.
|
|
// FIXME: It seems wierd to trigger a front-end method from here...
|
|
|
|
// We simply invalidate the
|
|
// corresponding rectangle of the contentview.
|
|
|
|
gui_win = GSWindowWithNumber(win);
|
|
|
|
n = [window->exposedRects count];
|
|
if( n > 0 )
|
|
{
|
|
NSView *v;
|
|
NSValue *val[n];
|
|
int i;
|
|
|
|
v = [gui_win contentView];
|
|
|
|
[window->exposedRects getObjects: val];
|
|
for( i = 0; i < n; ++i)
|
|
{
|
|
NSRect rect = [val[i] rectValue];
|
|
[v setNeedsDisplayInRect: rect];
|
|
}
|
|
}
|
|
|
|
// Restore the exposed rectangles and the region
|
|
[window->exposedRects removeAllObjects];
|
|
XDestroyRegion (window->region);
|
|
window->region = XCreateRegion();
|
|
XSetClipMask (dpy, window->gc, None);
|
|
}
|
|
|
|
- (BOOL) capturemouse: (int)win
|
|
{
|
|
int ret;
|
|
gswindow_device_t *window;
|
|
|
|
window = WINDOW_WITH_TAG(win);
|
|
if (!window)
|
|
return NO;
|
|
|
|
ret = XGrabPointer(dpy, window->ident, False,
|
|
PointerMotionMask | ButtonReleaseMask | ButtonPressMask,
|
|
GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
|
|
|
|
if (ret != GrabSuccess)
|
|
NSDebugLLog(@"XGTrace", @"Failed to grab pointer %d\n", win);
|
|
else
|
|
{
|
|
grab_window = window;
|
|
NSDebugLLog(@"XGTrace", @"Grabbed pointer %d\n", win);
|
|
}
|
|
return (ret == GrabSuccess) ? YES : NO;
|
|
}
|
|
|
|
- (void) releasemouse
|
|
{
|
|
NSDebugLLog(@"XGTrace", @"Released pointer\n");
|
|
XUngrabPointer(dpy, CurrentTime);
|
|
grab_window = NULL;
|
|
}
|
|
|
|
- (void) setinputfocus: (int)win
|
|
{
|
|
gswindow_device_t *window = WINDOW_WITH_TAG(win);
|
|
|
|
if (win == 0 || window == 0)
|
|
{
|
|
NSDebugLLog(@"Focus", @"Setting focus to unknown win %d", win);
|
|
return;
|
|
}
|
|
|
|
NSDebugLLog(@"XGTrace", @"DPSsetinputfocus: %d", win);
|
|
/*
|
|
* If we have an outstanding request to set focus to this window,
|
|
* we don't want to do it again.
|
|
*/
|
|
if (win == generic.desiredFocusWindow && generic.focusRequestNumber != 0)
|
|
{
|
|
NSDebugLLog(@"Focus", @"Focus already set on %d", window->number);
|
|
return;
|
|
}
|
|
|
|
NSDebugLLog(@"Focus", @"Setting focus to %d", window->number);
|
|
generic.desiredFocusWindow = win;
|
|
generic.focusRequestNumber = XNextRequest(dpy);
|
|
generic.desiredOrderedWindow = 0;
|
|
XSetInputFocus(dpy, window->ident, RevertToParent, generic.lastTime);
|
|
[inputServer ximFocusICWindow: window];
|
|
}
|
|
|
|
/*
|
|
* Instruct window manager that the specified window is 'key', 'main', or
|
|
* just a normal window.
|
|
*/
|
|
- (void) setinputstate: (int)st : (int)win
|
|
{
|
|
NSDebugLLog(@"XGTrace", @"DPSsetinputstate: %d : %d", st, win);
|
|
if ((generic.wm & XGWM_WINDOWMAKER) != 0)
|
|
{
|
|
gswindow_device_t *window = WINDOW_WITH_TAG(win);
|
|
XEvent event;
|
|
|
|
if (win == 0 || window == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
event.xclient.type = ClientMessage;
|
|
event.xclient.message_type = generic.titlebar_state_atom;
|
|
event.xclient.format = 32;
|
|
event.xclient.display = dpy;
|
|
event.xclient.window = window->ident;
|
|
event.xclient.data.l[0] = st;
|
|
event.xclient.data.l[1] = 0;
|
|
event.xclient.data.l[2] = 0;
|
|
event.xclient.data.l[3] = 0;
|
|
XSendEvent(dpy, DefaultRootWindow(dpy), False,
|
|
SubstructureRedirectMask, &event);
|
|
}
|
|
}
|
|
|
|
- (void *) serverDevice
|
|
{
|
|
return dpy;
|
|
}
|
|
|
|
- (void *) windowDevice: (int)win
|
|
{
|
|
static Window ptrloc;
|
|
gswindow_device_t *window;
|
|
|
|
window = WINDOW_WITH_TAG(win);
|
|
if (window != NULL)
|
|
ptrloc = window->ident;
|
|
else
|
|
ptrloc = 0;
|
|
return &ptrloc;
|
|
}
|
|
|
|
/* Cursor Ops */
|
|
typedef struct _xgps_cursor_id_t {
|
|
Cursor c;
|
|
} xgps_cursor_id_t;
|
|
|
|
static char xgps_blank_cursor_bits [] = {
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
|
|
|
static Cursor xgps_blank_cursor = None;
|
|
static BOOL cursor_hidden = NO;
|
|
|
|
- (Cursor) _blankCursor
|
|
{
|
|
if (xgps_blank_cursor == None)
|
|
{
|
|
Pixmap shape, mask;
|
|
XColor black, white;
|
|
Drawable drw = [self xDisplayRootWindowForScreen: defScreen];
|
|
|
|
shape = XCreatePixmapFromBitmapData(dpy, drw,
|
|
xgps_blank_cursor_bits,
|
|
16, 16, 1, 0, 1);
|
|
mask = XCreatePixmapFromBitmapData(dpy, drw,
|
|
xgps_blank_cursor_bits,
|
|
16, 16, 1, 0, 1);
|
|
black.red = black.green = black.blue = 0;
|
|
black = [self xColorFromColor: black forScreen: defScreen];
|
|
white.red = white.green = white.blue = 65535;
|
|
white = [self xColorFromColor: white forScreen: defScreen];
|
|
|
|
xgps_blank_cursor = XCreatePixmapCursor(dpy, shape, mask,
|
|
&white, &black, 0, 0);
|
|
XFreePixmap(dpy, shape);
|
|
XFreePixmap(dpy, mask);
|
|
}
|
|
return xgps_blank_cursor;
|
|
}
|
|
|
|
/*
|
|
set the cursor for a newly created window.
|
|
*/
|
|
|
|
- (void) _initializeCursorForXWindow: (Window) win
|
|
{
|
|
if (cursor_hidden)
|
|
{
|
|
XDefineCursor (dpy, win, [self _blankCursor]);
|
|
}
|
|
else
|
|
{
|
|
xgps_cursor_id_t *cid = [[NSCursor currentCursor] _cid];
|
|
|
|
XDefineCursor (dpy, win, cid->c);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
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
|
|
{
|
|
Window win;
|
|
NSMapEnumerator enumerator;
|
|
gswindow_device_t *d;
|
|
|
|
NSDebugLLog (@"NSCursor", @"_DPSsetcursor: cursor = %p, set = %d", c, set);
|
|
|
|
enumerator = NSEnumerateMapTable (windowmaps);
|
|
while (NSNextMapEnumeratorPair (&enumerator, (void**)&win, (void**)&d) == YES)
|
|
{
|
|
if (set)
|
|
XDefineCursor(dpy, win, c);
|
|
else
|
|
XUndefineCursor(dpy, win);
|
|
}
|
|
}
|
|
|
|
#define ALPHA_THRESHOLD 158
|
|
|
|
Pixmap
|
|
xgps_cursor_mask(Display *xdpy, Drawable draw, const char *data,
|
|
int w, int h, int colors)
|
|
{
|
|
int j, i;
|
|
unsigned char ialpha;
|
|
Pixmap pix;
|
|
int bitmapSize = ((w + 7) >> 3) * h; // (w/8) rounded up times height
|
|
char *aData = calloc(1, bitmapSize);
|
|
char *cData = aData;
|
|
|
|
if (colors == 4)
|
|
{
|
|
int k;
|
|
for (j = 0; j < h; j++)
|
|
{
|
|
k = 0;
|
|
for (i = 0; i < w; i++, k++)
|
|
{
|
|
if (k > 7)
|
|
{
|
|
cData++;
|
|
k = 0;
|
|
}
|
|
data += 3;
|
|
ialpha = (unsigned short)((char)*data++);
|
|
if (ialpha > ALPHA_THRESHOLD)
|
|
{
|
|
*cData |= (0x01 << k);
|
|
}
|
|
}
|
|
cData++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (j = 0; j < bitmapSize; j++)
|
|
{
|
|
*cData++ = 0xff;
|
|
}
|
|
}
|
|
|
|
pix = XCreatePixmapFromBitmapData(xdpy, draw, (char *)aData, w, h,
|
|
1L, 0L, 1);
|
|
free(aData);
|
|
return pix;
|
|
}
|
|
|
|
Pixmap
|
|
xgps_cursor_image(Display *xdpy, Drawable draw, const unsigned char *data,
|
|
int w, int h, int colors, XColor *fg, XColor *bg)
|
|
{
|
|
int j, i, min, max;
|
|
Pixmap pix;
|
|
int bitmapSize = ((w + 7) >> 3) * h; // w/8 rounded up multiplied by h
|
|
char *aData = calloc(1, bitmapSize);
|
|
char *cData = aData;
|
|
|
|
min = 1 << 16;
|
|
max = 0;
|
|
if (colors == 4 || colors == 3)
|
|
{
|
|
int k;
|
|
for (j = 0; j < h; j++)
|
|
{
|
|
k = 0;
|
|
for (i = 0; i < w; i++, k++)
|
|
{
|
|
/* colors is in the range 0..65535
|
|
and value is the percieved brightness, obtained by
|
|
averaging 0.3 red + 0.59 green + 0.11 blue
|
|
*/
|
|
int color = ((77 * data[0]) + (151 * data[1]) + (28 * data[2]));
|
|
|
|
if (k > 7)
|
|
{
|
|
cData++;
|
|
k = 0;
|
|
}
|
|
if (color > (1 << 15))
|
|
{
|
|
*cData |= (0x01 << k);
|
|
}
|
|
if (color < min)
|
|
{
|
|
min = color;
|
|
bg->red = (int)data[0] * 256;
|
|
bg->green = (int)data[1] * 256;
|
|
bg->blue = (int)data[2] * 256;
|
|
}
|
|
else if (color > max)
|
|
{
|
|
max = color;
|
|
fg->red = (int)data[0] * 256;
|
|
fg->green = (int)data[1] * 256;
|
|
fg->blue = (int)data[2] * 256;
|
|
}
|
|
data += 3;
|
|
if (colors == 4)
|
|
{
|
|
data++;
|
|
}
|
|
}
|
|
cData++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (j = 0; j < bitmapSize; j++)
|
|
{
|
|
if ((unsigned short)((char)*data++) > 128)
|
|
{
|
|
*cData |= (0x01 << j);
|
|
}
|
|
cData++;
|
|
}
|
|
}
|
|
|
|
pix = XCreatePixmapFromBitmapData(xdpy, draw, (char *)aData, w, h,
|
|
1L, 0L, 1);
|
|
free(aData);
|
|
return pix;
|
|
}
|
|
|
|
- (void) hidecursor
|
|
{
|
|
if (cursor_hidden)
|
|
return;
|
|
|
|
[self _DPSsetcursor: [self _blankCursor] : YES];
|
|
cursor_hidden = YES;
|
|
}
|
|
|
|
- (void) showcursor
|
|
{
|
|
if (cursor_hidden)
|
|
{
|
|
/* This just resets the cursor to the parent window's cursor.
|
|
I'm not even sure it's needed */
|
|
[self _DPSsetcursor: None : NO];
|
|
/* Reset the current cursor */
|
|
[[NSCursor currentCursor] set];
|
|
}
|
|
cursor_hidden = NO;
|
|
}
|
|
|
|
- (void) standardcursor: (int)style : (void **)cid
|
|
{
|
|
xgps_cursor_id_t *cursor;
|
|
cursor = NSZoneMalloc([self zone], sizeof(xgps_cursor_id_t));
|
|
switch (style)
|
|
{
|
|
case GSArrowCursor:
|
|
cursor->c = XCreateFontCursor(dpy, XC_left_ptr);
|
|
break;
|
|
case GSIBeamCursor:
|
|
cursor->c = XCreateFontCursor(dpy, XC_xterm);
|
|
break;
|
|
default:
|
|
cursor->c = XCreateFontCursor(dpy, XC_left_ptr);
|
|
break;
|
|
}
|
|
if (cid)
|
|
*cid = (void *)cursor;
|
|
}
|
|
|
|
- (void) imagecursor: (NSPoint)hotp : (int) w : (int) h : (int)colors : (const char *)image : (void **)cid
|
|
{
|
|
xgps_cursor_id_t *cursor;
|
|
Pixmap source, mask;
|
|
unsigned int maxw, maxh;
|
|
XColor fg, bg;
|
|
|
|
/* FIXME: We might create a blank cursor here? */
|
|
if (image == NULL || w <= 0 || h <= 0)
|
|
{
|
|
*cid = NULL;
|
|
return;
|
|
}
|
|
|
|
/* FIXME: Handle this better or return an error? */
|
|
XQueryBestCursor(dpy, ROOT, w, h, &maxw, &maxh);
|
|
if ((unsigned int)w > maxw)
|
|
w = maxw;
|
|
if ((unsigned int)h > maxh)
|
|
h = maxh;
|
|
|
|
cursor = NSZoneMalloc([self zone], sizeof(xgps_cursor_id_t));
|
|
source = xgps_cursor_image(dpy, ROOT, image, w, h, colors, &fg, &bg);
|
|
mask = xgps_cursor_mask(dpy, ROOT, image, w, h, colors);
|
|
bg = [self xColorFromColor: bg forScreen: defScreen];
|
|
fg = [self xColorFromColor: fg forScreen: defScreen];
|
|
|
|
cursor->c = XCreatePixmapCursor(dpy, source, mask, &fg, &bg,
|
|
(int)hotp.x, (int)(h - hotp.y));
|
|
XFreePixmap(dpy, source);
|
|
XFreePixmap(dpy, mask);
|
|
if (cid)
|
|
*cid = (void *)cursor;
|
|
}
|
|
|
|
- (void) setcursorcolor: (NSColor *)fg : (NSColor *)bg : (void*) cid
|
|
{
|
|
XColor xf, xb;
|
|
xgps_cursor_id_t *cursor;
|
|
|
|
cursor = (xgps_cursor_id_t *)cid;
|
|
if (cursor == NULL)
|
|
NSLog(@"Invalidparam: Invalid cursor");
|
|
|
|
[self _DPSsetcursor: cursor->c : YES];
|
|
/* Special hack: Don't set the color when fg == nil. Used by NSCursor
|
|
to just set the cursor but not the color. */
|
|
if (fg == nil)
|
|
{
|
|
return;
|
|
}
|
|
|
|
fg = [fg colorUsingColorSpaceName: NSDeviceRGBColorSpace];
|
|
bg = [bg colorUsingColorSpaceName: NSDeviceRGBColorSpace];
|
|
xf.red = 65535 * [fg redComponent];
|
|
xf.green = 65535 * [fg greenComponent];
|
|
xf.blue = 65535 * [fg blueComponent];
|
|
xb.red = 65535 * [bg redComponent];
|
|
xb.green = 65535 * [bg greenComponent];
|
|
xb.blue = 65535 * [bg blueComponent];
|
|
xf = [self xColorFromColor: xf forScreen: defScreen];
|
|
xb = [self xColorFromColor: xb forScreen: defScreen];
|
|
|
|
XRecolorCursor(dpy, cursor->c, &xf, &xb);
|
|
}
|
|
|
|
static NSWindowDepth
|
|
_computeDepth(int class, int bpp)
|
|
{
|
|
int spp = 0;
|
|
int bitValue = 0;
|
|
int bps = 0;
|
|
NSWindowDepth depth = 0;
|
|
|
|
switch (class)
|
|
{
|
|
case GrayScale:
|
|
case StaticGray:
|
|
bitValue = _GSGrayBitValue;
|
|
spp = 1;
|
|
break;
|
|
case PseudoColor:
|
|
case StaticColor:
|
|
bitValue = _GSCustomBitValue;
|
|
spp = 1;
|
|
break;
|
|
case DirectColor:
|
|
case TrueColor:
|
|
bitValue = _GSRGBBitValue;
|
|
spp = 3;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
bps = (bpp/spp);
|
|
depth = (bitValue | bps);
|
|
|
|
return depth;
|
|
}
|
|
|
|
- (NSArray *)screenList
|
|
{
|
|
/* I guess screen numbers are in order starting from zero, but we
|
|
put the main screen first */
|
|
int i;
|
|
int count = ScreenCount(dpy);
|
|
NSMutableArray *screens = [NSMutableArray arrayWithCapacity: count];
|
|
if (count > 0)
|
|
[screens addObject: [NSNumber numberWithInt: defScreen]];
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
if (i != defScreen)
|
|
[screens addObject: [NSNumber numberWithInt: i]];
|
|
}
|
|
return screens;
|
|
}
|
|
|
|
- (NSWindowDepth) windowDepthForScreen: (int) screen_num
|
|
{
|
|
Screen *screen;
|
|
int class = 0, bpp = 0;
|
|
|
|
screen = XScreenOfDisplay(dpy, screen_num);
|
|
if (screen == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
bpp = screen->root_depth;
|
|
class = screen->root_visual->class;
|
|
|
|
return _computeDepth(class, bpp);
|
|
}
|
|
|
|
- (const NSWindowDepth *) availableDepthsForScreen: (int) screen_num
|
|
{
|
|
Screen *screen;
|
|
int class = 0;
|
|
int index = 0;
|
|
int ndepths = 0;
|
|
NSZone *defaultZone = NSDefaultMallocZone();
|
|
NSWindowDepth *depths = 0;
|
|
|
|
if (dpy == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
screen = XScreenOfDisplay(dpy, screen_num);
|
|
if (screen == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
// Allocate the memory for the array and fill it in.
|
|
ndepths = screen->ndepths;
|
|
class = screen->root_visual->class;
|
|
depths = NSZoneMalloc(defaultZone, sizeof(NSWindowDepth)*(ndepths + 1));
|
|
for (index = 0; index < ndepths; index++)
|
|
{
|
|
int depth = screen->depths[index].depth;
|
|
depths[index] = _computeDepth(class, depth);
|
|
}
|
|
depths[index] = 0; // terminate with a zero.
|
|
|
|
return depths;
|
|
}
|
|
|
|
- (NSSize) resolutionForScreen: (int)screen_num
|
|
{
|
|
int res_x, res_y;
|
|
|
|
if (screen_num < 0 || screen_num >= ScreenCount(dpy))
|
|
{
|
|
NSLog(@"Invalidparam: no screen %d", screen_num);
|
|
return NSMakeSize(0,0);
|
|
}
|
|
// This does not take virtual displays into account!!
|
|
res_x = DisplayWidth(dpy, screen_num) /
|
|
(DisplayWidthMM(dpy, screen_num) / 25.4);
|
|
res_y = DisplayHeight(dpy, screen_num) /
|
|
(DisplayHeightMM(dpy, screen_num) / 25.4);
|
|
|
|
return NSMakeSize(res_x, res_y);
|
|
}
|
|
|
|
- (NSRect) boundsForScreen: (int)screen
|
|
{
|
|
if (screen < 0 || screen >= ScreenCount(dpy))
|
|
{
|
|
NSLog(@"Invalidparam: no screen %d", screen);
|
|
return NSZeroRect;
|
|
}
|
|
return NSMakeRect(0, 0, DisplayWidth(dpy, screen),
|
|
DisplayHeight(dpy, screen));
|
|
}
|
|
|
|
@end
|
|
|