From 2ca7818d89df84500316c3940d9931a096bbfd33 Mon Sep 17 00:00:00 2001 From: alexm Date: Tue, 6 Jul 2004 20:20:31 +0000 Subject: [PATCH] Reorganize top-level view handling and implement -gui-managed window decorations. git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@19687 72102866-910b-0410-8b05-ffd578937521 --- ChangeLog | 22 + .../Additions/GNUstepGUI/GSDisplayServer.h | 5 + Headers/AppKit/NSWindow.h | 35 +- Source/GNUmakefile | 4 +- Source/GSDisplayServer.m | 6 + Source/GSStandardWindowDecorationView.m | 549 ++++++++++++++++++ Source/GSWindowDecorationView.h | 100 ++++ Source/GSWindowDecorationView.m | 293 ++++++++++ Source/NSPanel.m | 63 +- Source/NSWindow.m | 342 +++++------ 10 files changed, 1152 insertions(+), 267 deletions(-) create mode 100644 Source/GSStandardWindowDecorationView.m create mode 100644 Source/GSWindowDecorationView.h create mode 100644 Source/GSWindowDecorationView.m diff --git a/ChangeLog b/ChangeLog index aca61fc3c..a18096710 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,25 @@ +2004-07-06 22:15 Alexander Malmberg + + * Headers/Additions/GNUstepGUI/GSDisplayServer.h: Add + -handlesWindowDecorations. + * Headers/AppKit/NSWindow.h: Document _frame ivar and add update + for -gui-managed window decorations. + (+minFrameWidthWithTitle:styleMask:): Change return type to float. + * Source/GNUmakefile: Add GSWindowDecorationView.m and + GSStandardWindowDecorationView.m . + * Source/GSDisplayServer.m (-handlesWindowDecorations): Provide a + default implementation. + * Source/NSPanel.m (-sendEvent:): Reimplement using + -_sendEvent:becomesKeyOnlyIfNeeded: . + (setControl): Only call -setStringValue: on the cell if it doesn't + respond to -setTitle: . + * Source/NSWindow.m: Reorganize management of the top-level view. + Implement -gui-managed window decorations. + (-_sendEvent:becomesKeyOnlyIfNeeded:): New method. + (-sendEvent:): Reimplement using -_sendEvent:becomesKeyOnlyIfNeeded: . + * Source/GSWindowDecorationView.h, Source/GSWindowDecorationView.m, + Source/GSStandardWindowDecorationView.m: New files. + 2004-07-05 Gregory John Casamento * Source/NSToolbar.m: [NSToolbar _setWindow:] added logic diff --git a/Headers/Additions/GNUstepGUI/GSDisplayServer.h b/Headers/Additions/GNUstepGUI/GSDisplayServer.h index 26148f941..3790f4d57 100644 --- a/Headers/Additions/GNUstepGUI/GSDisplayServer.h +++ b/Headers/Additions/GNUstepGUI/GSDisplayServer.h @@ -72,6 +72,8 @@ APPKIT_EXPORT NSString * GSScreenNumber; - glContextClass; - glPixelFormatClass; +- (BOOL) handlesWindowDecorations; + /* Drag and drop support. */ + (BOOL) addDragTypes: (NSArray*)types toWindow: (NSWindow *)win; + (BOOL) removeDragTypes: (NSArray*)types fromWindow: (NSWindow *)win; @@ -109,7 +111,10 @@ APPKIT_EXPORT NSString * GSScreenNumber; - (int) window: (NSRect)frame : (NSBackingStoreType)type : (unsigned int)style : (int)screen; - (void) termwindow: (int) win; + +/* Only if handlesWindowDecorations returns YES. */ - (void) stylewindow: (unsigned int) style : (int) win; + - (void) windowbacking: (NSBackingStoreType)type : (int) win; - (void) titlewindow: (NSString *) window_title : (int) win; - (void) miniwindow: (int) win; diff --git a/Headers/AppKit/NSWindow.h b/Headers/AppKit/NSWindow.h index a62e2e6a5..05e2a43a3 100644 --- a/Headers/AppKit/NSWindow.h +++ b/Headers/AppKit/NSWindow.h @@ -60,6 +60,8 @@ @class NSWindowController; @class NSCachedImageRep; +@class GSWindowDecorationView; + /* * Window levels are taken from MacOS-X * NSDesktopWindowLevel is copied from Window maker and is intended to be @@ -101,12 +103,39 @@ APPKIT_EXPORT NSSize NSTokenSize; @interface NSWindow : NSResponder { + /* + A window really has three interesting frames: + + The screen frame. This is the frame of the _entire_ window on the screen, + including all decorations and borders (regardless of where they come from). + (On X, we can only guess what the screen frame is.) + + The window frame. This is the frame of the backend window for this window, + and is thus the base of the coordinate system for the window. IOW, it's + the frame of the area we can draw into. + + The contect rect. This is the frame of the content view. + + Wrt. size, ScreenFrame >= WindowFrame >= ContentRect. When -gui doesn't + manage the window decorations, WindowFrame == ContentRect. When -gui does + manage the window decorations, WindowFrame will include the decorations, + and ScreenFrame == WindowFrame. + + + To get coordinate transforms and stuff right wrt. OpenStep, we really want + the window frame here. However, for hysterical reasons, _frame is actually + the screen frame. (The other rectangles/sizes passed around in NSWindow + methods are likely a mix of screen and window frames.) Only if -gui manages + decorations will this match the semantics properly. + */ NSRect _frame; + + NSSize _minimumSize; NSSize _maximumSize; NSSize _increments; NSString *_autosaveName; - id _wv; + GSWindowDecorationView *_wv; id _contentView; id _firstResponder; id _futureFirstResponder; @@ -193,8 +222,8 @@ APPKIT_EXPORT NSSize NSTokenSize; + (NSRect) frameRectForContentRect: (NSRect)aRect styleMask: (unsigned int)aStyle; -+ (NSRect) minFrameWidthWithTitle: (NSString *)aTitle - styleMask: (unsigned int)aStyle; ++ (float) minFrameWidthWithTitle: (NSString *)aTitle + styleMask: (unsigned int)aStyle; /* diff --git a/Source/GNUmakefile b/Source/GNUmakefile index 03771d0cf..973c26435 100644 --- a/Source/GNUmakefile +++ b/Source/GNUmakefile @@ -186,7 +186,9 @@ GSNibTemplates.m \ GSNibCompatibility.m \ GSTitleView.m \ GSToolbar.m \ -GSToolbarView.m +GSToolbarView.m \ +GSStandardWindowDecorationView.m \ +GSWindowDecorationView.m # Turn off NSMenuItem warning that NSMenuItem conforms to , # but does not implement 's methods itself (it inherits diff --git a/Source/GSDisplayServer.m b/Source/GSDisplayServer.m index 0c31fe16f..9e7a0cfa7 100644 --- a/Source/GSDisplayServer.m +++ b/Source/GSDisplayServer.m @@ -278,6 +278,12 @@ GSCurrentServer(void) } +- (BOOL) handlesWindowDecorations +{ + return YES; +} + + /* Drag and drop support. */ /** Convienience method that calls -addDragTypes:toWindow: using the server that controls win. diff --git a/Source/GSStandardWindowDecorationView.m b/Source/GSStandardWindowDecorationView.m new file mode 100644 index 000000000..6247275fb --- /dev/null +++ b/Source/GSStandardWindowDecorationView.m @@ -0,0 +1,549 @@ +/** GSStandardWindowDecorationView + + Copyright (C) 2004 Free Software Foundation, Inc. + + Author: Alexander Malmberg + Date: 2004-03-24 + + This file is part of the GNUstep GUI Library. + + 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; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "GSWindowDecorationView.h" + +#include + +#include "AppKit/NSApplication.h" +#include "AppKit/NSButton.h" +#include "AppKit/NSImage.h" +#include "AppKit/NSScreen.h" +#include "AppKit/NSStringDrawing.h" +#include "AppKit/NSWindow.h" +#include "AppKit/PSOperators.h" +#include "GNUstepGUI/GSDisplayServer.h" + + +@implementation GSStandardWindowDecorationView + +/* These include the black border. */ +#define TITLE_HEIGHT 23.0 +#define RESIZE_HEIGHT 9.0 + ++(void) offsets: (float *)l : (float *)r : (float *)t : (float *)b + forStyleMask: (unsigned int)style +{ + if (style + & (NSTitledWindowMask | NSClosableWindowMask + | NSMiniaturizableWindowMask | NSResizableWindowMask)) + *l = *r = *t = *b = 1.0; + else + *l = *r = *t = *b = 0.0; + + if (style + & (NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask)) + { + *t = TITLE_HEIGHT; + } + if (style & NSResizableWindowMask) + { + *b = RESIZE_HEIGHT; + } +} + ++ (float) minFrameWidthWithTitle: (NSString *)aTitle + styleMask: (unsigned int)aStyle +{ + float l, r, t, b, width; + [self offsets: &l : &r : &t : &b + forStyleMask: aStyle]; + + width = l + r; + + if (aStyle & NSTitledWindowMask) + width += [aTitle sizeWithAttributes: nil].width; + + return width; +} + + +static NSDictionary *titleTextAttributes[3]; +static NSColor *titleColor[3]; + +-(void) updateRects +{ + if (hasTitleBar) + titleBarRect = NSMakeRect(0.0, _frame.size.height - TITLE_HEIGHT, + _frame.size.width, TITLE_HEIGHT); + if (hasResizeBar) + resizeBarRect = NSMakeRect(0.0, 0.0, _frame.size.width, RESIZE_HEIGHT); + + if (hasCloseButton) + { + closeButtonRect = NSMakeRect( + _frame.size.width - 15 - 4, _frame.size.height - 15 - 4, 15, 15); + [closeButton setFrame: closeButtonRect]; + } + + if (hasMiniaturizeButton) + { + miniaturizeButtonRect = NSMakeRect(4, _frame.size.height - 15 - 4, + 15, 15); + [miniaturizeButton setFrame: miniaturizeButtonRect]; + } +} + +- initWithFrame: (NSRect)frame + window: (NSWindow *)w +{ + if (!titleTextAttributes[0]) + { + titleTextAttributes[0] = [[NSMutableDictionary alloc] + initWithObjectsAndKeys: + [NSFont titleBarFontOfSize: 0], NSFontAttributeName, + [NSColor windowFrameTextColor], NSForegroundColorAttributeName, + nil]; + titleTextAttributes[1] = [[NSMutableDictionary alloc] + initWithObjectsAndKeys: + [NSFont titleBarFontOfSize: 0], NSFontAttributeName, + [NSColor blackColor], NSForegroundColorAttributeName, /* TODO: need a named color for this */ + nil]; + titleTextAttributes[2] = [[NSMutableDictionary alloc] + initWithObjectsAndKeys: + [NSFont titleBarFontOfSize: 0], NSFontAttributeName, + [NSColor windowFrameTextColor], NSForegroundColorAttributeName, + nil]; + + titleColor[0] = RETAIN([NSColor windowFrameColor]); + titleColor[1] = RETAIN([NSColor lightGrayColor]); + titleColor[2] = RETAIN([NSColor darkGrayColor]); + } + + self = [super initWithFrame: frame + window: w]; + if (!self) return nil; + + if ([w styleMask] + & (NSTitledWindowMask | NSClosableWindowMask + | NSMiniaturizableWindowMask)) + { + hasTitleBar = YES; + } + if ([w styleMask] & NSTitledWindowMask) + isTitled = YES; + if ([w styleMask] & NSClosableWindowMask) + { + hasCloseButton = YES; + + closeButton = [[NSButton alloc] init]; + [closeButton setRefusesFirstResponder: YES]; + [closeButton setButtonType: NSMomentaryChangeButton]; + [closeButton setImagePosition: NSImageOnly]; + [closeButton setBordered: YES]; + [closeButton setImage: [NSImage imageNamed: @"common_Close"]]; + [closeButton setAlternateImage: [NSImage imageNamed: @"common_CloseH"]]; + [closeButton setTarget: window]; + /* TODO: -performClose: should (but doesn't currently) highlight the + button, which is wrong here. When -performClose: is fixed, we'll need a + different method here. */ + [closeButton setAction: @selector(performClose:)]; + [self addSubview: closeButton]; + RELEASE(closeButton); + } + if ([w styleMask] & NSMiniaturizableWindowMask) + { + hasMiniaturizeButton = YES; + + miniaturizeButton = [[NSButton alloc] init]; + [miniaturizeButton setRefusesFirstResponder: YES]; + [miniaturizeButton setButtonType: NSMomentaryChangeButton]; + [miniaturizeButton setImagePosition: NSImageOnly]; + [miniaturizeButton setBordered: YES]; + [miniaturizeButton setImage: + [NSImage imageNamed: @"common_Miniaturize"]]; + [miniaturizeButton setAlternateImage: + [NSImage imageNamed: @"common_MiniaturizeH"]]; + [miniaturizeButton setTarget: window]; + /* TODO: -performMiniaturize: should (but doesn't currently) highlight + the button, which is wrong here, just like -performClose: above. */ + [miniaturizeButton setAction: @selector(performMiniaturize:)]; + [self addSubview: miniaturizeButton]; + RELEASE(miniaturizeButton); + } + if ([w styleMask] & NSResizableWindowMask) + hasResizeBar = YES; + + [self updateRects]; + + return self; +} + + +-(void) drawTitleBar +{ +static const NSRectEdge edges[4] = {NSMinXEdge, NSMaxYEdge, + NSMaxXEdge, NSMinYEdge}; + float grays[3][4] = + {{NSLightGray, NSLightGray, NSDarkGray, NSDarkGray}, + {NSWhite, NSWhite, NSDarkGray, NSDarkGray}, + {NSLightGray, NSLightGray, NSBlack, NSBlack}}; + NSRect workRect; + NSString *title = [window title]; + + /* + Draw the black border towards the rest of the window. (The outer black + border is drawn in -drawRect: since it might be drawn even if we don't have + a title bar. + */ + [[NSColor blackColor] set]; + PSmoveto(0, NSMinY(titleBarRect) + 0.5); + PSrlineto(titleBarRect.size.width, 0); + PSstroke(); + + /* + Draw the button-like border. + */ + workRect = titleBarRect; + workRect.origin.x += 1; + workRect.origin.y += 1; + workRect.size.width -= 2; + workRect.size.height -= 2; + + workRect = NSDrawTiledRects(workRect, workRect, edges, grays[inputState], 4); + + /* + Draw the background. + */ + [titleColor[inputState] set]; + NSRectFill(workRect); + + /* Draw the title. */ + if (isTitled) + { + NSSize titleSize; + + if (hasMiniaturizeButton) + { + workRect.origin.x += 17; + workRect.size.width -= 17; + } + if (hasCloseButton) + { + workRect.size.width -= 17; + } + + titleSize = [title sizeWithAttributes: titleTextAttributes[inputState]]; + if (titleSize.width <= workRect.size.width) + workRect.origin.x += NSMidX(workRect) - titleSize.width / 2; + workRect.origin.y = NSMidY(workRect) - titleSize.height / 2; + workRect.size.height = titleSize.height; + [title drawInRect: workRect + withAttributes: titleTextAttributes[inputState]]; + } +} + +-(void) drawResizeBar +{ + [[NSColor lightGrayColor] set]; + PSrectfill(1.0, 1.0, resizeBarRect.size.width - 2.0, RESIZE_HEIGHT - 3.0); + + PSsetlinewidth(1.0); + + [[NSColor blackColor] set]; + PSmoveto(0.0, 0.5); + PSlineto(resizeBarRect.size.width, 0.5); + PSstroke(); + + [[NSColor darkGrayColor] set]; + PSmoveto(1.0, RESIZE_HEIGHT - 0.5); + PSlineto(resizeBarRect.size.width - 1.0, RESIZE_HEIGHT - 0.5); + PSstroke(); + + [[NSColor whiteColor] set]; + PSmoveto(1.0, RESIZE_HEIGHT - 1.5); + PSlineto(resizeBarRect.size.width - 1.0, RESIZE_HEIGHT - 1.5); + PSstroke(); + + + /* Only draw the notches if there's enough space. */ + if (resizeBarRect.size.width < 30 * 2) + return; + + [[NSColor darkGrayColor] set]; + PSmoveto(27.5, 1.0); + PSlineto(27.5, RESIZE_HEIGHT - 2.0); + PSmoveto(resizeBarRect.size.width - 28.5, 1.0); + PSlineto(resizeBarRect.size.width - 28.5, RESIZE_HEIGHT - 2.0); + PSstroke(); + + [[NSColor whiteColor] set]; + PSmoveto(28.5, 1.0); + PSlineto(28.5, RESIZE_HEIGHT - 2.0); + PSmoveto(resizeBarRect.size.width - 27.5, 1.0); + PSlineto(resizeBarRect.size.width - 27.5, RESIZE_HEIGHT - 2.0); + PSstroke(); +} + +-(void) drawRect: (NSRect)rect +{ + if (hasTitleBar && NSIntersectsRect(rect, titleBarRect)) + { + [self drawTitleBar]; + } + + if (hasResizeBar && NSIntersectsRect(rect, resizeBarRect)) + { + [self drawResizeBar]; + } + + if (hasResizeBar || hasTitleBar) + { + PSsetlinewidth(1.0); + [[NSColor blackColor] set]; + if (NSMinX(rect) < 1.0) + { + PSmoveto(0.5, 0.0); + PSlineto(0.5, _frame.size.height); + PSstroke(); + } + if (NSMaxX(rect) > _frame.size.width - 1.0) + { + PSmoveto(_frame.size.width - 0.5, 0.0); + PSlineto(_frame.size.width - 0.5, _frame.size.height); + PSstroke(); + } + if (NSMaxY(rect) > _frame.size.height - 1.0) + { + PSmoveto(0.0, _frame.size.height - 0.5); + PSlineto(_frame.size.width, _frame.size.height - 0.5); + PSstroke(); + } + if (NSMinY(rect) < 1.0) + { + PSmoveto(0.0, 0.5); + PSlineto(_frame.size.width, 0.5); + PSstroke(); + } + } + + [super drawRect: rect]; +} + + +-(void) setTitle: (NSString *)newTitle +{ + if (isTitled) + [self setNeedsDisplayInRect: titleBarRect]; +} + +-(void) setInputState: (int)state +{ + NSAssert(state >= 0 && state <= 2, @"Invalid state!"); + [super setInputState: state]; + if (hasTitleBar) + [self setNeedsDisplayInRect: titleBarRect]; +} + +-(void) setDocumentEdited: (BOOL)flag +{ + if (flag) + { + [closeButton setImage: [NSImage imageNamed: @"common_CloseBroken"]]; + [closeButton setAlternateImage: + [NSImage imageNamed: @"common_CloseBrokenH"]]; + } + else + { + [closeButton setImage: [NSImage imageNamed: @"common_Close"]]; + [closeButton setAlternateImage: + [NSImage imageNamed: @"common_CloseH"]]; + } +} + + +-(NSPoint) mouseLocationOnScreenOutsideOfEventStream +{ + int screen = [[window screen] screenNumber]; + return [GSServerForWindow(window) mouseLocationOnScreen: screen + window: NULL]; +} + +-(void) moveWindowStartingWithEvent: (NSEvent *)event +{ + unsigned int mask = NSLeftMouseDraggedMask | NSLeftMouseUpMask; + NSEvent *currentEvent = event; + NSDate *distantPast = [NSDate distantPast]; + NSPoint delta, point; + + delta = [event locationInWindow]; + + [window _captureMouse: nil]; + do + { + while (currentEvent && [currentEvent type] != NSLeftMouseUp) + { + currentEvent = [_window nextEventMatchingMask: mask + untilDate: distantPast + inMode: NSEventTrackingRunLoopMode + dequeue: YES]; + } + + point = [self mouseLocationOnScreenOutsideOfEventStream]; + [window setFrameOrigin: NSMakePoint(point.x - delta.x, + point.y - delta.y)]; + + if (currentEvent && [currentEvent type] == NSLeftMouseUp) + break; + + + currentEvent = [_window nextEventMatchingMask: mask + untilDate: nil + inMode: NSEventTrackingRunLoopMode + dequeue: YES]; + } while ([currentEvent type] != NSLeftMouseUp); + [window _releaseMouse: nil]; +} + + +static NSRect calc_new_frame(NSRect frame, NSPoint point, NSPoint firstPoint, + int mode, NSSize minSize, NSSize maxSize) +{ + NSRect newFrame = frame; + newFrame.origin.y = point.y - firstPoint.y; + newFrame.size.height = NSMaxY(frame) - newFrame.origin.y; + if (newFrame.size.height < minSize.height) + { + newFrame.size.height = minSize.height; + newFrame.origin.y = NSMaxY(frame) - newFrame.size.height; + } + + if (mode == 0) + { + newFrame.origin.x = point.x - firstPoint.x; + newFrame.size.width = NSMaxX(frame) - newFrame.origin.x; + + if (newFrame.size.width < minSize.width) + { + newFrame.size.width = minSize.width; + newFrame.origin.x = NSMaxX(frame) - newFrame.size.width; + } + } + else if (mode == 1) + { + newFrame.size.width = point.x - frame.origin.x + frame.size.width + - firstPoint.x; + + if (newFrame.size.width < minSize.width) + { + newFrame.size.width = minSize.width; + newFrame.origin.x = frame.origin.x; + } + } + return newFrame; +} + +-(void) resizeWindowStartingWithEvent: (NSEvent *)event +{ + unsigned int mask = NSLeftMouseDraggedMask | NSLeftMouseUpMask; + NSEvent *currentEvent = event; + NSDate *distantPast = [NSDate distantPast]; + NSPoint firstPoint, point; + NSRect newFrame, frame; + NSSize minSize, maxSize; + + /* + 0 drag lower left corner + 1 drag lower right corner + 2 drag lower edge + */ + int mode; + + + firstPoint = [event locationInWindow]; + if (resizeBarRect.size.width < 30 * 2 + && firstPoint.x < resizeBarRect.size.width / 2) + mode = 0; + else if (firstPoint.x > resizeBarRect.size.width - 29) + mode = 1; + else if (firstPoint.x < 29) + mode = 0; + else + mode = 2; + + frame = [window frame]; + minSize = [window minSize]; + maxSize = [window maxSize]; + + [window _captureMouse: nil]; + do + { + while (currentEvent && [currentEvent type] != NSLeftMouseUp) + { + currentEvent = [_window nextEventMatchingMask: mask + untilDate: distantPast + inMode: NSEventTrackingRunLoopMode + dequeue: YES]; + } + + point = [self mouseLocationOnScreenOutsideOfEventStream]; + newFrame = calc_new_frame(frame, point, firstPoint, mode, minSize, maxSize); + + if (currentEvent && [currentEvent type] == NSLeftMouseUp) + break; + + currentEvent = [_window nextEventMatchingMask: mask + untilDate: nil + inMode: NSEventTrackingRunLoopMode + dequeue: YES]; + } while ([currentEvent type] != NSLeftMouseUp); + [window _releaseMouse: nil]; + + [window setFrame: newFrame display: YES]; +} + +-(BOOL) acceptsFirstMouse: (NSEvent*)theEvent +{ + return YES; +} + +-(void) mouseDown: (NSEvent *)event +{ + NSPoint p = [self convertPoint: [event locationInWindow] fromView: nil]; + + if (NSPointInRect(p, contentRect)) + return; + + if (NSPointInRect(p, titleBarRect)) + { + [self moveWindowStartingWithEvent: event]; + return; + } + + if (NSPointInRect(p, resizeBarRect)) + { + [self resizeWindowStartingWithEvent: event]; + return; + } +} + +- (void) setFrame: (NSRect)frameRect +{ + [super setFrame: frameRect]; + [self updateRects]; +} + +@end + diff --git a/Source/GSWindowDecorationView.h b/Source/GSWindowDecorationView.h new file mode 100644 index 000000000..e9146b63a --- /dev/null +++ b/Source/GSWindowDecorationView.h @@ -0,0 +1,100 @@ +/** GSWindowDecorationView + + Copyright (C) 2004 Free Software Foundation, Inc. + + Author: Alexander Malmberg + Date: 2004-03-24 + + This file is part of the GNUstep GUI Library. + + 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; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef _GNUstep_H_GSWindowDecorationView +#define _GNUstep_H_GSWindowDecorationView + +#include +#include "AppKit/NSView.h" + +@class NSWindow; + +@protocol GSWindowDecorator +- (id) newWindowDecorationViewWithFrame: (NSRect)frame + window: (NSWindow *)window; + +- (NSRect) contentRectForFrameRect: (NSRect)aRect + styleMask: (unsigned int)aStyle; +- (NSRect) frameRectForContentRect: (NSRect)aRect + styleMask: (unsigned int)aStyle; +- (float) minFrameWidthWithTitle: (NSString *)aTitle + styleMask: (unsigned int)aStyle; +@end + + +/* +Abstract superclass for the top-level view in each window. This view is +responsible for managing window decorations. Concrete subclasses may do +this, either directly, or indirectly (by using the backend). +*/ +@interface GSWindowDecorationView : NSView +{ + NSWindow *window; /* not retained */ + int windowNumber; + + NSRect contentRect; + + int inputState; + BOOL documentEdited; +} ++(id) windowDecorator; + +- initWithFrame: (NSRect)frame + window: (NSWindow *)w; + +-(void) setContentView: (NSView *)contentView; + +/* +Called when the backend window is created or destroyed. When it's destroyed, +windowNumber will be 0. +*/ +-(void) setWindowNumber: (int)windowNumber; + +-(void) setTitle: (NSString *)title; +-(void) setInputState: (int)state; +-(void) setDocumentEdited: (BOOL)flag; +@end + + +/* +Standard OPENSTEP-ish window decorations. +*/ +@class NSButton; + +@interface GSStandardWindowDecorationView : GSWindowDecorationView +{ + BOOL hasTitleBar, hasResizeBar, hasCloseButton, hasMiniaturizeButton; + BOOL isTitled; + NSRect titleBarRect; + NSRect resizeBarRect; + NSRect closeButtonRect; + NSRect miniaturizeButtonRect; + + NSButton *closeButton, *miniaturizeButton; +} +@end + +#endif + diff --git a/Source/GSWindowDecorationView.m b/Source/GSWindowDecorationView.m new file mode 100644 index 000000000..eaf33d258 --- /dev/null +++ b/Source/GSWindowDecorationView.m @@ -0,0 +1,293 @@ +/** GSWindowDecorationView + + Copyright (C) 2004 Free Software Foundation, Inc. + + Author: Alexander Malmberg + Date: 2004-03-24 + + This file is part of the GNUstep GUI Library. + + 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; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "GSWindowDecorationView.h" + +#include + +#include "AppKit/NSColor.h" +#include "AppKit/NSWindow.h" +#include "GNUstepGUI/GSDisplayServer.h" + + +struct NSWindow_struct +{ + @defs(NSWindow) +}; + + +/* +Manage window decorations by using the backend functions. This only works +on backends that can handle window decorations. +*/ +@interface GSBackendWindowDecorationView : GSWindowDecorationView +@end + + +/* +GSWindowDecorationView implementation. +*/ +@implementation GSWindowDecorationView + ++(id) windowDecorator +{ + if ([GSCurrentServer() handlesWindowDecorations]) + return [GSBackendWindowDecorationView self]; + else + return [GSStandardWindowDecorationView self]; +} + + ++(id) newWindowDecorationViewWithFrame: (NSRect)frame + window: (NSWindow *)aWindow +{ + return [[self alloc] initWithFrame: frame + window: aWindow]; +} + + ++(void) offsets: (float *)l : (float *)r : (float *)t : (float *)b + forStyleMask: (unsigned int)style +{ + [self subclassResponsibility: _cmd]; +} + ++ (NSRect) contentRectForFrameRect: (NSRect)aRect + styleMask: (unsigned int)aStyle +{ + float t, b, l, r; + + [self offsets: &l : &r : &t : &b + forStyleMask: aStyle]; + aRect.size.width -= l + r; + aRect.size.height -= t + b; + aRect.origin.x += l; + aRect.origin.y += b; + return aRect; +} + ++ (NSRect) frameRectForContentRect: (NSRect)aRect + styleMask: (unsigned int)aStyle +{ + float t, b, l, r; + + [self offsets: &l : &r : &t : &b + forStyleMask: aStyle]; + aRect.size.width += l + r; + aRect.size.height += t + b; + aRect.origin.x -= l; + aRect.origin.y -= b; + return aRect; +} + ++ (float) minFrameWidthWithTitle: (NSString *)aTitle + styleMask: (unsigned int)aStyle +{ + [self subclassResponsibility: _cmd]; + return 0.0; +} + + +/* +Internal helpers. + +Returns the internal window frame rect for a given (screen) frame. +*/ ++(NSRect) windowFrameRectForFrameRect: (NSRect)aRect + styleMask: (unsigned int)aStyle +{ + aRect.origin = NSZeroPoint; + return aRect; +} + +/* +Returns the content rect for a given window frame. +*/ ++(NSRect) contentRectForWindowFrameRect: (NSRect)aRect + styleMask: (unsigned int)aStyle +{ + return [self contentRectForFrameRect: aRect styleMask: aStyle]; +} + + +- initWithFrame: (NSRect)frame +{ + NSAssert(NO, @"Tried to create GSWindowDecorationView without a window!"); + return nil; +} + +- initWithFrame: (NSRect)frame + window: (NSWindow *)w +{ + frame = [isa windowFrameRectForFrameRect: frame + styleMask: [w styleMask]]; + + self = [super initWithFrame: frame]; + if (!self) + return nil; + + window = w; + contentRect = frame; + contentRect = + [isa contentRectForWindowFrameRect: contentRect + styleMask: [window styleMask]]; + + return self; +} + +/* + * Special setFrame: implementation - a minimal autoresize mechanism + */ +- (void) setFrame: (NSRect)frameRect +{ + NSSize oldSize = _frame.size; + NSView *cv = [_window contentView]; + + frameRect = [isa windowFrameRectForFrameRect: frameRect + styleMask: [window styleMask]]; + + _autoresizes_subviews = NO; + [super setFrame: frameRect]; + + contentRect = [isa contentRectForWindowFrameRect: frameRect + styleMask: [window styleMask]]; + + // Safety Check. + [cv setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable]; + [cv resizeWithOldSuperviewSize: oldSize]; +} + +- (void) setContentView: (NSView *)contentView +{ + NSSize oldSize; + + [contentView setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable]; + [self addSubview: contentView]; + + oldSize = [contentView frame].size; + oldSize.width += _frame.size.width - contentRect.size.width; + oldSize.height += _frame.size.height - contentRect.size.height; + [contentView resizeWithOldSuperviewSize: oldSize]; + [contentView setFrameOrigin: NSMakePoint(contentRect.origin.x, + contentRect.origin.y)]; +} + +-(void) setWindowNumber: (int)theWindowNumber +{ + windowNumber = theWindowNumber; + if (!windowNumber) + return; + + [GSServerForWindow(window) titlewindow: [window title] : windowNumber]; + [GSServerForWindow(window) setinputstate: inputState : windowNumber]; + [GSServerForWindow(window) docedited: documentEdited : windowNumber]; +} + +-(void) setTitle: (NSString *)title +{ + if (windowNumber) + [GSServerForWindow(window) titlewindow: title : windowNumber]; +} +-(void) setInputState: (int)state +{ + inputState = state; + if (windowNumber) + [GSServerForWindow(window) setinputstate: inputState : windowNumber]; +} +-(void) setDocumentEdited: (BOOL)flag +{ + documentEdited = flag; + if (windowNumber) + [GSServerForWindow(window) docedited: documentEdited : windowNumber]; +} + + +- (BOOL) isOpaque +{ + return YES; +} + +- (void) drawRect: (NSRect)rect +{ + NSColor *c = [_window backgroundColor]; + + if (NSIntersectsRect(rect, contentRect)) + { + [c set]; + NSRectFill(contentRect); + } +} + + + +- initWithCoder: (NSCoder*)aCoder +{ + NSAssert(NO, @"The top-level window view should never be encoded."); + return nil; +} +-(void) encodeWithCoder: (NSCoder*)aCoder +{ + NSAssert(NO, @"The top-level window view should never be encoded."); +} + +@end + + + +@implementation GSBackendWindowDecorationView + ++(void) offsets: (float *)l : (float *)r : (float *)t : (float *)b + forStyleMask: (unsigned int)style +{ + [GSCurrentServer() styleoffsets: l : r : t : b : style]; +} ++ (float) minFrameWidthWithTitle: (NSString *)aTitle + styleMask: (unsigned int)aStyle +{ + /* TODO: we could at least guess... */ + return 0.0; +} + ++(NSRect) windowFrameRectForFrameRect: (NSRect)aRect + styleMask: (unsigned int)aStyle +{ + float l, r, t, b; + [self offsets: &l : &r : &t : &b forStyleMask: aStyle]; + aRect.size.width -= l + r; + aRect.size.height -= t + b; + return aRect; +} + +/* +Returns the content rect for a given window frame. +*/ ++(NSRect) contentRectForWindowFrameRect: (NSRect)aRect + styleMask: (unsigned int)aStyle +{ + return aRect; +} + +@end + diff --git a/Source/NSPanel.m b/Source/NSPanel.m index 276fe87af..471621940 100644 --- a/Source/NSPanel.m +++ b/Source/NSPanel.m @@ -194,65 +194,8 @@ static NSString *defaultTitle = @" "; - (void) sendEvent: (NSEvent*)theEvent { -/* -Code shared with [NSWindow -sendEvent:], remember to update both places. -*/ - NSView *v; - NSEventType type; - - type = [theEvent type]; - if (type == NSLeftMouseDown) - { - if (_f.visible) - { - BOOL wasKey = _f.is_key; - - if (_f.has_closed == NO) - { - v = [_contentView hitTest: [theEvent locationInWindow]]; - if (_f.is_key == NO) - { - /* NSPanel modification: check becomesKeyOnlyIfNeeded. */ - if (!_becomesKeyOnlyIfNeeded || [v needsPanelToBecomeKey]) - [self makeKeyAndOrderFront: self]; - } - /* Activate the app *after* making the receiver key, as app - activation tries to make the previous key window key. */ - if ([NSApp isActive] == NO - && (NSWindow*)self != [NSApp iconWindow]) - { - [NSApp activateIgnoringOtherApps: YES]; - } - if (_firstResponder != v) - { - [self makeFirstResponder: v]; - } - if (_lastView) - { - DESTROY(_lastView); - } - if (wasKey == YES || [v acceptsFirstMouse: theEvent] == YES) - { - if ([NSHelpManager isContextHelpModeActive]) - { - [v helpRequested: theEvent]; - } - else - { - ASSIGN(_lastView, v); - [v mouseDown: theEvent]; - } - } - else - { - [self mouseDown: theEvent]; - } - } - _lastPoint = [theEvent locationInWindow]; - } - return; - } - [super sendEvent: theEvent]; + [self _sendEvent: theEvent + becomesKeyOnlyIfNeeded: _becomesKeyOnlyIfNeeded]; } @end /* NSPanel */ @@ -504,7 +447,7 @@ setControl(NSView* content, id control, NSString *title) { [control setTitle: title]; } - if ([control respondsToSelector: @selector(setStringValue:)]) + else if ([control respondsToSelector: @selector(setStringValue:)]) { [control setStringValue: title]; } diff --git a/Source/NSWindow.m b/Source/NSWindow.m index 780bd5c2b..e8df511a0 100644 --- a/Source/NSWindow.m +++ b/Source/NSWindow.m @@ -47,31 +47,37 @@ #include #include -#include "AppKit/NSDocument.h" -#include "AppKit/NSWindow.h" -#include "AppKit/NSWindowController.h" #include "AppKit/NSApplication.h" #include "AppKit/NSButtonCell.h" -#include "AppKit/NSMenu.h" -#include "AppKit/NSImage.h" -#include "AppKit/NSTextFieldCell.h" -#include "AppKit/NSTextField.h" -#include "AppKit/NSFont.h" -#include "AppKit/NSColor.h" -#include "AppKit/NSScreen.h" -#include "AppKit/NSView.h" -#include "AppKit/NSCursor.h" -#include "AppKit/PSOperators.h" -#include "AppKit/NSDragging.h" -#include "AppKit/NSPasteboard.h" -#include "AppKit/NSHelpManager.h" -#include "AppKit/NSGraphics.h" #include "AppKit/NSCachedImageRep.h" +#include "AppKit/NSColor.h" +#include "AppKit/NSColorList.h" +#include "AppKit/NSCursor.h" +#include "AppKit/NSDocument.h" +#include "AppKit/NSDragging.h" +#include "AppKit/NSFont.h" +#include "AppKit/NSGraphics.h" +#include "AppKit/NSHelpManager.h" +#include "AppKit/NSImage.h" +#include "AppKit/NSMenu.h" +#include "AppKit/NSPasteboard.h" +#include "AppKit/NSScreen.h" +#include "AppKit/NSTextField.h" +#include "AppKit/NSTextFieldCell.h" #include "AppKit/NSToolbar.h" +#include "AppKit/NSView.h" +#include "AppKit/NSWindow.h" +#include "AppKit/NSWindowController.h" +#include "AppKit/PSOperators.h" #include "GNUstepGUI/GSTrackingRect.h" #include "GNUstepGUI/GSDisplayServer.h" #include "GNUstepGUI/GSToolbarView.h" +#include "GSWindowDecorationView.h" + +static id windowDecorator; + + BOOL GSViewAcceptsDrag(NSView *v, id dragInfo); static NSArray *modes = nil; @@ -102,7 +108,7 @@ static NSArray *modes = nil; /* This method handles all normal displaying. It is set to be run on each runloop iteration for each window that's on-screen. The performer is -added then the window is ordered in and re-added each time it is run. +added when the window is ordered in and re-added each time it is run. If the window is ordered out, the performer is cancelled. The reason why this performer is always added, as opposed to adding it @@ -398,53 +404,6 @@ static NSCell *tileCell = nil; -@interface GSWindowView : NSView -{ -} -@end - -@implementation GSWindowView - -- (BOOL) isOpaque -{ - return YES; -} - -- (void) drawRect: (NSRect)rect -{ - NSColor *c = [[self window] backgroundColor]; - - NSDebugLLog(@"NSView", @"-drawRect: %@ for %@ in window %p (%@)", - NSStringFromRect(rect), self, _window, - NSStringFromRect([_window frame])); - [c set]; - NSRectFill(rect); -} - -/* - * Special setFrame: implementation - a minimal autoresize mechanism - */ -- (void) setFrame: (NSRect)frameRect -{ - NSSize oldSize = _frame.size; - NSView *cv = [_window contentView]; - - _autoresizes_subviews = NO; - [super setFrame: frameRect]; - // Safety Check. - [cv setAutoresizingMask: (NSViewWidthSizable | NSViewHeightSizable)]; - [cv resizeWithOldSuperviewSize: oldSize]; -} - -- (Class) classForCoder: (NSCoder*)aCoder -{ - if ([self class] == [GSWindowView class]) - return [super class]; - return [self class]; -} - -@end - /***************************************************************************** * * NSWindow @@ -546,52 +505,31 @@ static NSNotificationCenter *nc = nil; + (NSRect) contentRectForFrameRect: (NSRect)aRect styleMask: (unsigned int)aStyle { - float t, b, l, r; + if (!windowDecorator) + windowDecorator = [GSWindowDecorationView windowDecorator]; - [GSCurrentServer() styleoffsets: &l : &r : &t : &b : aStyle]; - aRect.size.width -= (l + r); - aRect.size.height -= (t + b); - aRect.origin.x += l; - aRect.origin.y += b; - return aRect; + return [windowDecorator contentRectForFrameRect: aRect + styleMask: aStyle]; } + (NSRect) frameRectForContentRect: (NSRect)aRect styleMask: (unsigned int)aStyle { - float t, b, l, r; + if (!windowDecorator) + windowDecorator = [GSWindowDecorationView windowDecorator]; - [GSCurrentServer() styleoffsets: &l : &r : &t : &b : aStyle]; - aRect.size.width += (l + r); - aRect.size.height += (t + b); - aRect.origin.x -= l; - aRect.origin.y -= b; - return aRect; + return [windowDecorator frameRectForContentRect: aRect + styleMask: aStyle]; } -+ (NSRect) minFrameWidthWithTitle: (NSString*)aTitle - styleMask: (unsigned int)aStyle ++ (float) minFrameWidthWithTitle: (NSString *)aTitle + styleMask: (unsigned int)aStyle { - float t, b, l, r; - NSRect f = NSZeroRect; + if (!windowDecorator) + windowDecorator = [GSWindowDecorationView windowDecorator]; - [GSCurrentServer() styleoffsets: &l : &r : &t : &b : aStyle]; - f.size.width = l + r; - f.size.height = t + b; - /* - * Assume that the width of the area needed for a button is equal to - * the height of the title bar. - */ - if (aStyle & NSClosableWindowMask) - f.size.width += t; - if (aStyle & NSMiniaturizableWindowMask) - f.size.width += t; - /* - * FIXME - title width has to be better determined than this. - * need to get correct values from font. - */ - f.size.width += [aTitle length] * 10; - return f; + return [windowDecorator minFrameWidthWithTitle: aTitle + styleMask: aStyle]; } /* default Screen and window depth */ @@ -641,6 +579,7 @@ many times. if (_windowNum) { + [_wv setWindowNumber: 0]; [GSServerForWindow(self) termwindow: _windowNum]; NSMapRemove(windowmaps, (void*)_windowNum); _windowNum = 0; @@ -680,7 +619,7 @@ many times. deallocation of the window's views ! - some of them might be retained for some other reason by the programmer or by other parts of the code */ - TEST_RELEASE(_wv); + DESTROY(_wv); TEST_RELEASE(_fieldEditor); TEST_RELEASE(_backgroundColor); TEST_RELEASE(_representedFilename); @@ -713,7 +652,7 @@ many times. [super dealloc]; } -- (void) _initBackendWindow: (NSRect)frame +- (void) _initBackendWindow { int screenNumber; NSCountedSet *dragTypes; @@ -735,7 +674,12 @@ many times. } screenNumber = [_screen screenNumber]; - _windowNum = [srv window: frame : _backingType : _styleMask : screenNumber]; + + _windowNum = + [srv window: _frame + : _backingType + : _styleMask + : screenNumber]; [srv setwindowlevel: [self level] : _windowNum]; NSMapInsert (windowmaps, (void*)_windowNum, self); @@ -745,9 +689,9 @@ many times. _gstate = GSDefineGState(context); DPSgrestore(context); - frame = [NSWindow contentRectForFrameRect: frame styleMask: _styleMask]; if (NSIsEmptyRect([_wv frame])) { + NSRect frame = _frame; frame.origin = NSZeroPoint; [_wv setFrame: frame]; } @@ -783,8 +727,6 @@ many times. } /* Other stuff we need to do for deferred windows */ - if (_windowTitle != nil) - [srv titlewindow: _windowTitle : _windowNum]; if (!NSEqualSizes(_minimumSize, NSZeroSize)) [self setMinSize: _minimumSize]; if (!NSEqualSizes(_maximumSize, NSZeroSize)) @@ -792,7 +734,9 @@ many times. if (!NSEqualSizes(_increments, NSZeroSize)) [self setResizeIncrements: _increments]; - NSDebugLLog(@"NSWindow", @"Created NSWindow frame %@", + [_wv setWindowNumber: _windowNum]; + + NSDebugLLog(@"NSWindow", @"Created NSWindow window frame %@", NSStringFromRect(_frame)); } @@ -868,6 +812,9 @@ many times. windowmaps = NSCreateMapTable(NSIntMapKeyCallBacks, NSNonRetainedObjectMapValueCallBacks, 20); + if (!windowDecorator) + windowDecorator = [GSWindowDecorationView windowDecorator]; + /* Initialize attributes and flags */ [super init]; [self _initDefaults]; @@ -881,7 +828,7 @@ many times. _frame = [NSWindow frameRectForContentRect: contentRect styleMask: aStyle]; _minimumSize = NSMakeSize(_frame.size.width - contentRect.size.width + 1, - _frame.size.height - contentRect.size.height + 1); + _frame.size.height - contentRect.size.height + 1); _maximumSize = NSMakeSize (10e4, 10e4); [self setNextResponder: NSApp]; @@ -891,8 +838,9 @@ many times. /* Create the window view */ cframe.origin = NSZeroPoint; - cframe.size = contentRect.size; - _wv = [[GSWindowView allocWithZone: [self zone]] initWithFrame: cframe]; + cframe.size = _frame.size; + _wv = [windowDecorator newWindowDecorationViewWithFrame: cframe + window: self]; [_wv viewWillMoveToWindow: self]; /* Create the content view */ @@ -911,15 +859,28 @@ many times. if (flag == NO) { NSDebugLLog(@"NSWindow", @"Creating NSWindow\n"); - [self _initBackendWindow: _frame]; + [self _initBackendWindow]; } else - NSDebugLLog(@"NSWindow", @"Defering NSWindow creation\n"); + NSDebugLLog(@"NSWindow", @"Deferring NSWindow creation\n"); + + [nc addObserver: self + selector: @selector(colorListChanged:) + name: NSColorListChangedNotification + object: nil]; NSDebugLLog(@"NSWindow", @"NSWindow end of init\n"); return self; } +-(void) colorListChanged:(NSNotification*)notif +{ + if ([[notif object] isEqual: [NSColorList colorListNamed:@"System"]]) + { + [_wv setNeedsDisplay:YES]; + } +} + /* * Accessing the content view */ @@ -935,21 +896,18 @@ many times. { if (aView == nil) { - aView = AUTORELEASE([[NSView alloc] initWithFrame: _frame]); + aView = AUTORELEASE([[NSView alloc] + initWithFrame: + [NSWindow contentRectForFrameRect: _frame + styleMask: _styleMask]]); } if (_contentView != nil) { [_contentView removeFromSuperview]; } _contentView = aView; - [_contentView setAutoresizingMask: (NSViewWidthSizable - | NSViewHeightSizable)]; - [_wv addSubview: _contentView]; - [_contentView resizeWithOldSuperviewSize: [_contentView frame].size]; - [_contentView setFrameOrigin: [_wv bounds].origin]; - NSAssert1 ([[_wv subviews] count] == 1, - @"window's view has %d subviews!", [[_wv subviews] count]); + [_wv setContentView: _contentView]; [_contentView setNextResponder: self]; } @@ -982,14 +940,13 @@ many times. { if ([_windowTitle isEqual: aString] == NO) { - ASSIGN(_windowTitle, aString); - [self setMiniwindowTitle: aString]; - if (_windowNum > 0) - [GSServerForWindow(self) titlewindow: aString : _windowNum]; + ASSIGNCOPY(_windowTitle, aString); + [self setMiniwindowTitle: _windowTitle]; + [_wv setTitle: _windowTitle]; if (_f.menu_exclude == NO && _f.has_opened == YES) { [NSApp changeWindowsItem: self - title: aString + title: _windowTitle filename: NO]; } } @@ -1003,14 +960,13 @@ many times. [aString stringByDeletingLastPathComponent]]; if ([_windowTitle isEqual: aString] == NO) { - ASSIGN(_windowTitle, aString); - [self setMiniwindowTitle: aString]; - if (_windowNum > 0) - [GSServerForWindow(self) titlewindow: aString : _windowNum]; + ASSIGNCOPY(_windowTitle, aString); + [self setMiniwindowTitle: _windowTitle]; + [_wv setTitle: _windowTitle]; if (_f.menu_exclude == NO && _f.has_opened == YES) { [NSApp changeWindowsItem: self - title: aString + title: _windowTitle filename: YES]; } } @@ -1241,7 +1197,7 @@ many times. [_firstResponder becomeKeyWindow]; } - [GSServerForWindow(self) setinputstate: GSTitleBarKey : _windowNum]; + [_wv setInputState: GSTitleBarKey]; [GSServerForWindow(self) setinputfocus: _windowNum]; [self resetCursorRects]; [nc postNotificationName: NSWindowDidBecomeKeyNotification object: self]; @@ -1256,7 +1212,7 @@ many times. _f.is_main = YES; if (_f.is_key == NO) { - [GSServerForWindow(self) setinputstate: GSTitleBarMain : _windowNum]; + [_wv setInputState: GSTitleBarMain]; } [nc postNotificationName: NSWindowDidBecomeMainNotification object: self]; NSDebugLLog(@"NSWindow", @"%@ is now main window", [self title]); @@ -1454,7 +1410,7 @@ many times. && [NSApp isHidden] == NO && _f.visible == NO) { - NSRect nframe = [self constrainFrameRect: _frame + NSRect nframe = [self constrainFrameRect: _frame toScreen: [self screen]]; if (_windowNum) [self setFrame: nframe display: NO]; @@ -1464,16 +1420,16 @@ many times. // create deferred window if (_windowNum == 0) { - [self _initBackendWindow: _frame]; + [self _initBackendWindow]; display = YES; } } // Draw content before backend window ordering if (display) - [_contentView display]; + [_wv display]; else if (place != NSWindowOut) - [_contentView displayIfNeeded]; + [_wv displayIfNeeded]; /* The backend will keep us below the current key window unless we force it not too */ @@ -1520,7 +1476,7 @@ many times. } if ([self isKeyWindow] == YES) { - [srv setinputstate: GSTitleBarKey : _windowNum]; + [_wv setInputState: GSTitleBarKey]; [srv setinputfocus: _windowNum]; } _f.visible = YES; @@ -1543,12 +1499,11 @@ many times. if (_f.is_main == YES) { - [GSServerForWindow(self) setinputstate: GSTitleBarMain : _windowNum]; + [_wv setInputState: GSTitleBarMain]; } else { - [GSServerForWindow(self) setinputstate: GSTitleBarNormal - : _windowNum]; + [_wv setInputState: GSTitleBarNormal]; } [self discardCursorRects]; @@ -1563,13 +1518,11 @@ many times. _f.is_main = NO; if (_f.is_key == YES) { - [GSServerForWindow(self) setinputstate: GSTitleBarKey - : _windowNum]; + [_wv setInputState: GSTitleBarKey]; } else { - [GSServerForWindow(self) setinputstate: GSTitleBarNormal - : _windowNum]; + [_wv setInputState: GSTitleBarNormal]; } [nc postNotificationName: NSWindowDidResignMainNotification object: self]; } @@ -1774,8 +1727,6 @@ many times. else { _frame = frameRect; - frameRect = [NSWindow contentRectForFrameRect: frameRect - styleMask: _styleMask]; frameRect.origin = NSZeroPoint; [_wv setFrame: frameRect]; } @@ -1855,14 +1806,9 @@ many times. */ - (NSPoint) convertBaseToScreen: (NSPoint)aPoint { - GSDisplayServer *srv = GSCurrentServer(); - NSPoint screenPoint; - float t, b, l, r; - - [srv styleoffsets: &l : &r : &t : &b : _styleMask]; - screenPoint.x = _frame.origin.x + aPoint.x + l; - screenPoint.y = _frame.origin.y + aPoint.y + b; - + NSPoint screenPoint; + screenPoint.x = _frame.origin.x + aPoint.x; + screenPoint.y = _frame.origin.y + aPoint.y; return screenPoint; } @@ -1872,14 +1818,9 @@ many times. */ - (NSPoint) convertScreenToBase: (NSPoint)aPoint { - GSDisplayServer *srv = GSCurrentServer(); - NSPoint basePoint; - float t, b, l, r; - - [srv styleoffsets: &l : &r : &t : &b : _styleMask]; - basePoint.x = aPoint.x - _frame.origin.x - l; - basePoint.y = aPoint.y - _frame.origin.y - b; - + NSPoint basePoint; + basePoint.x = aPoint.x - _frame.origin.x; + basePoint.y = aPoint.y - _frame.origin.y; return basePoint; } @@ -2320,7 +2261,7 @@ resetCursorRectsForView(NSView *theView) /* Make sure we're not defered */ if (_windowNum == 0) { - [self _initBackendWindow: _frame]; + [self _initBackendWindow]; } /* * Ensure that we have a miniwindow counterpart. @@ -2460,8 +2401,7 @@ resetCursorRectsForView(NSView *theView) { [NSApp updateWindowsItem: self]; } - if (_windowNum) - [GSServerForWindow(self) docedited: flag : _windowNum]; + [_wv setDocumentEdited: flag]; } } @@ -2879,7 +2819,8 @@ resetCursorRectsForView(NSView *theView) /** Handles mouse and other events sent to the receiver by NSApplication. Do not invoke this method directly. */ -- (void) sendEvent: (NSEvent*)theEvent +- (void) _sendEvent: (NSEvent*)theEvent + becomesKeyOnlyIfNeeded: (BOOL)becomesKeyOnlyIfNeeded { NSView *v; NSEventType type; @@ -2906,18 +2847,17 @@ resetCursorRectsForView(NSView *theView) switch (type) { case NSLeftMouseDown: -/* -Code shared with [NSPanel -sendEvent:], remember to update both places. -*/ { BOOL wasKey = _f.is_key; if (_f.has_closed == NO) { - v = [_contentView hitTest: [theEvent locationInWindow]]; + v = [_wv hitTest: [theEvent locationInWindow]]; if (_f.is_key == NO && _windowLevel != NSDesktopWindowLevel) { - [self makeKeyAndOrderFront: self]; + /* NSPanel modification: check becomesKeyOnlyIfNeeded. */ + if (!becomesKeyOnlyIfNeeded || [v needsPanelToBecomeKey]) + [self makeKeyAndOrderFront: self]; } /* Activate the app *after* making the receiver key, as app activation tries to make the previous key window key. */ @@ -2964,27 +2904,27 @@ Code shared with [NSPanel -sendEvent:], remember to update both places. break; case NSOtherMouseDown: - v = [_contentView hitTest: [theEvent locationInWindow]]; + v = [_wv hitTest: [theEvent locationInWindow]]; [v otherMouseDown: theEvent]; _lastPoint = [theEvent locationInWindow]; break; case NSOtherMouseUp: - v = [_contentView hitTest: [theEvent locationInWindow]]; + v = [_wv hitTest: [theEvent locationInWindow]]; [v otherMouseUp: theEvent]; _lastPoint = [theEvent locationInWindow]; break; case NSRightMouseDown: { - v = [_contentView hitTest: [theEvent locationInWindow]]; + v = [_wv hitTest: [theEvent locationInWindow]]; [v rightMouseDown: theEvent]; _lastPoint = [theEvent locationInWindow]; } break; case NSRightMouseUp: - v = [_contentView hitTest: [theEvent locationInWindow]]; + v = [_wv hitTest: [theEvent locationInWindow]]; [v rightMouseUp: theEvent]; _lastPoint = [theEvent locationInWindow]; break; @@ -2996,15 +2936,15 @@ Code shared with [NSPanel -sendEvent:], remember to update both places. switch (type) { case NSLeftMouseDragged: - v = [_contentView hitTest: [theEvent locationInWindow]]; + v = [_wv hitTest: [theEvent locationInWindow]]; [v mouseDragged: theEvent]; break; case NSOtherMouseDragged: - v = [_contentView hitTest: [theEvent locationInWindow]]; + v = [_wv hitTest: [theEvent locationInWindow]]; [v otherMouseDragged: theEvent]; break; case NSRightMouseDragged: - v = [_contentView hitTest: [theEvent locationInWindow]]; + v = [_wv hitTest: [theEvent locationInWindow]]; [v rightMouseDragged: theEvent]; break; default: @@ -3014,7 +2954,7 @@ Code shared with [NSPanel -sendEvent:], remember to update both places. * If the window is set to accept mouse movements, we need to * forward the mouse movement to the correct view. */ - v = [_contentView hitTest: [theEvent locationInWindow]]; + v = [_wv hitTest: [theEvent locationInWindow]]; [v mouseMoved: theEvent]; } break; @@ -3035,7 +2975,7 @@ Code shared with [NSPanel -sendEvent:], remember to update both places. * cursor update event. */ if (_f.cursor_rects_enabled) - (*ccImp)(self, ccSel, _contentView, theEvent); + (*ccImp)(self, ccSel, _wv, theEvent); } _lastPoint = [theEvent locationInWindow]; @@ -3074,7 +3014,7 @@ Code shared with [NSPanel -sendEvent:], remember to update both places. break; case NSScrollWheel: - v = [_contentView hitTest: [theEvent locationInWindow]]; + v = [_wv hitTest: [theEvent locationInWindow]]; [v scrollWheel: theEvent]; break; @@ -3113,8 +3053,6 @@ Code shared with [NSPanel -sendEvent:], remember to update both places. { NSRect rect = _frame; - rect = [NSWindow contentRectForFrameRect: rect - styleMask: _styleMask]; rect.origin = NSZeroPoint; [_wv setFrame: rect]; [_wv setNeedsDisplay: YES]; @@ -3179,7 +3117,7 @@ Code shared with [NSPanel -sendEvent:], remember to update both places. * to determine if we should send a cursor update * event. */ if (_f.cursor_rects_enabled) - (*ccImp)(self, ccSel, _contentView, theEvent); + (*ccImp)(self, ccSel, _wv, theEvent); } _lastPoint = NSMakePoint(-1, -1); @@ -3243,7 +3181,7 @@ Code shared with [NSPanel -sendEvent:], remember to update both places. { BOOL isEntry; - v = [_contentView hitTest: [theEvent locationInWindow]]; + v = [_wv hitTest: [theEvent locationInWindow]]; while (v != nil && ((NSViewPtr)v)->_rFlags.has_draginfo == 0) { v = [v superview]; @@ -3379,6 +3317,16 @@ Code shared with [NSPanel -sendEvent:], remember to update both places. } } +/** Handles mouse and other events sent to the receiver by NSApplication. + Do not invoke this method directly. +*/ +- (void) sendEvent: (NSEvent*)theEvent +{ + [self _sendEvent: theEvent + becomesKeyOnlyIfNeeded: NO]; +} + + - (BOOL) tryToPerform: (SEL)anAction with: (id)anObject { if ([super tryToPerform: anAction with: anObject]) @@ -3784,24 +3732,24 @@ Code shared with [NSPanel -sendEvent:], remember to update both places. */ - (NSData *) dataWithEPSInsideRect: (NSRect)rect { - return [_contentView dataWithEPSInsideRect: - [_contentView convertRect: rect fromView: nil]]; + return [_wv dataWithEPSInsideRect: + [_wv convertRect: rect fromView: nil]]; } - (NSData *)dataWithPDFInsideRect:(NSRect)aRect { - return [_contentView dataWithPDFInsideRect: - [_contentView convertRect: aRect fromView: nil]]; + return [_wv dataWithPDFInsideRect: + [_wv convertRect: aRect fromView: nil]]; } - (void) fax: (id)sender { - [_contentView fax: sender]; + [_wv fax: sender]; } - (void) print: (id)sender { - [_contentView print: sender]; + [_wv print: sender]; } /* @@ -4116,18 +4064,6 @@ Code shared with [NSPanel -sendEvent:], remember to update both places. [GSCurrentServer() releasemouse]; } -- (void) setContentViewSize: (NSSize)aSize -{ - NSRect r; - - r.origin = NSZeroPoint; - r.size = aSize; - if (_contentView) - { - [_contentView setFrame: r]; - } -} - - (void) _setVisible: (BOOL)flag { _f.visible = flag;