mirror of
https://github.com/gnustep/libs-gui.git
synced 2025-04-22 19:01:15 +00:00
Merge branch 'master' into NSStoryboard_branch
This commit is contained in:
commit
6e40a3be19
42 changed files with 1878 additions and 353 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -3,6 +3,7 @@ obj
|
|||
*.sum
|
||||
*.bundle
|
||||
*.service
|
||||
autom4te.cache
|
||||
config.log
|
||||
config.status
|
||||
config.cache
|
||||
|
@ -15,6 +16,7 @@ Source/config.h
|
|||
Source/Info-gnustep.plist
|
||||
Tests/gui/*/GNUmakefile
|
||||
Tools/speech/GSSpeechServer.app
|
||||
Tools/speech_recognizer/GSSpeechRecognitionServer.app
|
||||
*~
|
||||
|
||||
# Created by https://www.gitignore.io/api/xcode
|
||||
|
|
|
@ -5,16 +5,16 @@ compiler:
|
|||
- gcc
|
||||
env:
|
||||
- LIBRARY_COMBO=gnu-gnu-gnu
|
||||
- LIBRARY_COMBO=ng-gnu-gnu
|
||||
- LIBRARY_COMBO=ng-gnu-gnu BASE_ABI=--disable-mixedabi
|
||||
- LIBRARY_COMBO=ng-gnu-gnu RUNTIME_VERSION=gnustep-1.9
|
||||
- LIBRARY_COMBO=ng-gnu-gnu BASE_ABI=--disable-mixedabi RUNTIME_VERSION=gnustep-1.9
|
||||
- LIBRARY_COMBO=ng-gnu-gnu RUNTIME_VERSION=gnustep-2.0
|
||||
- LIBRARY_COMBO=ng-gnu-gnu BASE_ABI=--disable-mixedabi RUNTIME_VERSION=gnustep-2.0
|
||||
matrix:
|
||||
exclude:
|
||||
- compiler: gcc
|
||||
env: LIBRARY_COMBO=ng-gnu-gnu
|
||||
env: LIBRARY_COMBO=ng-gnu-gnu RUNTIME_VERSION=gnustep-1.9
|
||||
- compiler: gcc
|
||||
env: LIBRARY_COMBO=ng-gnu-gnu BASE_ABI=--disable-mixedabi
|
||||
env: LIBRARY_COMBO=ng-gnu-gnu BASE_ABI=--disable-mixedabi RUNTIME_VERSION=gnustep-1.9
|
||||
- compiler: gcc
|
||||
env: LIBRARY_COMBO=ng-gnu-gnu RUNTIME_VERSION=gnustep-2.0
|
||||
- compiler: gcc
|
||||
|
|
102
ChangeLog
102
ChangeLog
|
@ -1,3 +1,105 @@
|
|||
2020-03-12 Sergii Stoian <stoyan255@gmail.com>
|
||||
|
||||
* Model/GNUmakefile: do not overwrite ADDITIONAL_INCLUDE_DIRS
|
||||
value to help RPM build. In spec file ADDITIONAL_INCLUDE_DIRS can be sat
|
||||
to subdirectories which are create by RPM build tool.
|
||||
|
||||
2020-03-05 Sergii Stoian <stoyan255@gmail.com>
|
||||
|
||||
* Source/NSWindow.m (_applyFrame:): new helper method to do actual
|
||||
resizing.
|
||||
(setFrame:display:): use _applyFrame method.
|
||||
(applicationDidChangeScreenParameters:): Use _applyFrame: because our
|
||||
origin in OpenStep coordinates might be unchanged and `setFrame:display:`
|
||||
has check for it.
|
||||
|
||||
2020-02-28 Sergii Stoian <stoyan255@gmail.com>
|
||||
|
||||
* Source/NSWindow.m (center): always center window on main screen -
|
||||
monitor where user expects to see window.
|
||||
|
||||
2020-02-26 Sergii Stoian <stoyan255@gmail.com>
|
||||
|
||||
* Source/NSWindow.m (sendEvent:): removed usage of extra local variables
|
||||
in GSAppKitWindowMoved code block.
|
||||
|
||||
2020-02-23 Sergii Stoian <stoyan255@gmail.com>
|
||||
|
||||
* Source/NSWindow.m
|
||||
(applicationDidChangeScreenParameters:): quit while loop after
|
||||
screen was found.
|
||||
(sendEvent:): use `_screen` ivar to get screen befor frame change.
|
||||
|
||||
* Source/NSMenu.m (windowDidChangeScreen:): join two if statements.
|
||||
|
||||
2020-02-23 Fred Kiefer <FredKiefer@gmx.de>
|
||||
|
||||
* Headers/Additions/GNUstepGUI/GSXibLoading.h,
|
||||
* Source/GSXib5KeyedUnarchiver.m,
|
||||
* Source/GSXibLoading.m: Move more behaviour from the
|
||||
IBActionConnection5 and IBOutletConnection5 classes
|
||||
to the original ones.
|
||||
|
||||
2020-02-23 Fred Kiefer <FredKiefer@gmx.de>
|
||||
|
||||
* .travis.yml
|
||||
* travis-deps.sh: Try to keep up with Niels' changes in base.
|
||||
|
||||
2020-02-20 Sergii Stoian <stoyan255@gmail.com>
|
||||
|
||||
* Source/NSMenu.m (_setGeometry): take into account main screen
|
||||
origin when calculating horizontal menu postion.
|
||||
|
||||
* Source/NSApplication.m (_appIconInit): take into account main screen
|
||||
origin when placing application icon.
|
||||
|
||||
2020-02-13 Sergii Stoian <stoyan255@gmail.com>
|
||||
|
||||
* Source/NSWindow.m (setFrame:display:): use _screeForFrame: here
|
||||
to prevent `_screen` reassign - it will be reassigned in
|
||||
sendEvent: (GSAppKitWindowMoved event) after call to [self screen].
|
||||
(setFrameFromString:): removed unused code because _screenForFrame:
|
||||
never returns `nil`. Do not reassign `_screen` here.
|
||||
|
||||
2020-02-12 Sergii Stoian <stoyan255@gmail.com>
|
||||
|
||||
* Source/NSWindow.m (sendEvent:): set current screen to ivar and
|
||||
send WindowDidChangeScreen notification if window was moved to other
|
||||
screen.
|
||||
|
||||
* Source/NSScreen.m (mainScreen): returns screen of main menu if no
|
||||
key window exists. With this implementation default screen (screen at
|
||||
index 0 in screens array) should never be returned.
|
||||
|
||||
* Source/NSMenu.m (initWithTitle:): observe WindowDidBecomeKey and
|
||||
WindowDidChangeScreen notifications.
|
||||
(windowDidChangeScreen:): new method to handle observed notification
|
||||
added above. Moves menu to screen of key window for both cases: when
|
||||
key window moved to or activated on different screen.
|
||||
|
||||
2020-02-09 Fred Kiefer <FredKiefer@gmx.de>
|
||||
|
||||
* Source/NSFontDescriptor.m: Correct key for encoding and decoding.
|
||||
|
||||
2020-01-31 Sergii Stoian <stoyan255@gmail.com>
|
||||
|
||||
* Source/GSTitleView.m (mouseDown:): limit menu movement to screen
|
||||
frame for top/left/right edges. Menu can be moved to the bottom until
|
||||
title is completely visible.
|
||||
|
||||
2020-01-27 Sergii Stoian <stoyan255@gmail.com>
|
||||
|
||||
* Source/NSWindow.m (applicationDidChangeScreenParameters): take into
|
||||
account screen origin change during window position recalculation.
|
||||
|
||||
2020-01-26 Sergii Stoian <stoyan255@gmail.com>
|
||||
|
||||
* Source/NSWindow.m (initWithContentRect:styleMask:backing:defer:):
|
||||
added observer of NSApplicationDidChangeScreenParametersNotification.
|
||||
(applicationDidChangeScreenParameters:): callback for added notification -
|
||||
updates window position, set new screen object and saves frame if
|
||||
autosave name exists.
|
||||
|
||||
2020-01-23 Fred Kiefer <FredKiefer@gmx.de>
|
||||
|
||||
* Source/GSXib5KeyedUnarchiver.m: Remove NSWindowTemplate5.
|
||||
|
|
|
@ -178,6 +178,15 @@
|
|||
is meant to make things friendlier for slow computers.
|
||||
</p>
|
||||
</desc>
|
||||
<term>GSScaleFactor</term>
|
||||
<desc>
|
||||
<p>
|
||||
A floating point number, <code>1.0</code> by default. Scales
|
||||
GUI elements by the given factor for high-DPI monitors. DPI
|
||||
auto-detection on some platforms (only Windows, for now) will
|
||||
cause the default to appear to change.
|
||||
</p>
|
||||
</desc>
|
||||
<term>GSUnknownFileTool</term>
|
||||
<desc>
|
||||
<p>
|
||||
|
|
|
@ -86,6 +86,7 @@
|
|||
|
||||
@interface IBActionConnection: IBConnection
|
||||
{
|
||||
NSString *trigger;
|
||||
}
|
||||
@end
|
||||
|
||||
|
|
|
@ -18,6 +18,9 @@
|
|||
/* Define to 1 if you have the <flite/flite.h> header file. */
|
||||
#undef HAVE_FLITE_FLITE_H
|
||||
|
||||
/* Define to 1 if you have the pocketsphinx.h header file */
|
||||
#undef HAVE_POCKETSPHINX_POCKETSPHINX_EXPORT_H
|
||||
|
||||
/* Define to 1 if you have the `floorf' function. */
|
||||
#undef HAVE_FLOORF
|
||||
|
||||
|
|
|
@ -141,6 +141,7 @@
|
|||
#import <AppKit/NSArrayController.h>
|
||||
#import <AppKit/NSBezierPath.h>
|
||||
#import <AppKit/NSButtonTouchBarItem.h>
|
||||
#import <AppKit/NSColorSampler.h>
|
||||
#import <AppKit/NSColorSpace.h>
|
||||
#import <AppKit/NSComboBox.h>
|
||||
#import <AppKit/NSComboBoxCell.h>
|
||||
|
|
53
Headers/AppKit/NSColorSampler.h
Normal file
53
Headers/AppKit/NSColorSampler.h
Normal file
|
@ -0,0 +1,53 @@
|
|||
/* Definition of class NSColorSampler
|
||||
Copyright (C) 2020 Free Software Foundation, Inc.
|
||||
|
||||
By: Gregory John Casamento
|
||||
Date: Thu Mar 12 03:11:27 EDT 2020
|
||||
|
||||
This file is part of the GNUstep Library.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 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 Lesser General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110 USA.
|
||||
*/
|
||||
|
||||
#ifndef _NSColorSampler_h_GNUSTEP_GUI_INCLUDE
|
||||
#define _NSColorSampler_h_GNUSTEP_GUI_INCLUDE
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
#if OS_API_VERSION(MAC_OS_X_VERSION_10_0, GS_API_LATEST)
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
@class NSColor;
|
||||
|
||||
DEFINE_BLOCK_TYPE(GSColorSampleHandler, void, NSColor*);
|
||||
|
||||
@interface NSColorSampler : NSObject
|
||||
|
||||
- (void) showSamplerWithSelectionHandler: (GSColorSampleHandler)selectionHandler;
|
||||
|
||||
@end
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GS_API_MACOSX */
|
||||
|
||||
#endif /* _NSColorSampler_h_GNUSTEP_GUI_INCLUDE */
|
||||
|
|
@ -8,16 +8,16 @@
|
|||
* This file is part of GNUstep.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110
|
||||
* USA.
|
||||
|
|
|
@ -8,16 +8,16 @@
|
|||
* This file is part of GNUstep.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110
|
||||
* USA.
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#define _NSSpeechRecognizer_h_GNUSTEP_GUI_INCLUDE
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
#import <AppKit/AppKitDefines.h>
|
||||
|
||||
#if OS_API_VERSION(MAC_OS_X_VERSION_10_0, GS_API_LATEST)
|
||||
|
||||
|
@ -33,10 +34,55 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
@interface NSSpeechRecognizer : NSObject
|
||||
@protocol NSSpeechRecognizerDelegate;
|
||||
|
||||
@class NSArray, NSString, NSUUID;
|
||||
|
||||
@interface NSSpeechRecognizer : NSObject
|
||||
{
|
||||
id<NSSpeechRecognizerDelegate> _delegate;
|
||||
NSArray *_commands;
|
||||
NSString *_displayCommandsTitle;
|
||||
NSUUID *_uuid;
|
||||
BOOL _blocksOtherRecognizers;
|
||||
BOOL _listensInForegroundOnly;
|
||||
BOOL _appInForeground; // private
|
||||
BOOL _isListening;
|
||||
}
|
||||
|
||||
// Initialize
|
||||
- (instancetype) init;
|
||||
|
||||
- (id<NSSpeechRecognizerDelegate>) delegate;
|
||||
- (void) setDelegate: (id<NSSpeechRecognizerDelegate>) delegate;
|
||||
|
||||
// Configuring...
|
||||
- (NSArray *) commands;
|
||||
- (void) setCommands: (NSArray *)commands;
|
||||
|
||||
- (NSString *) displayCommandsTitle;
|
||||
- (void) setDisplayCommandsTitle: (NSString *)displayCommandsTitle;
|
||||
|
||||
- (BOOL) listensInForegroundOnly;
|
||||
- (void) setListensInForegroundOnly: (BOOL)listensInForegroundOnly;
|
||||
|
||||
- (BOOL) blocksOtherRecognizers;
|
||||
- (void) setBlocksOtherRecognizers: (BOOL)blocksOtherRecognizers;
|
||||
|
||||
// Listening
|
||||
- (void) startListening;
|
||||
- (void) stopListening;
|
||||
|
||||
@end
|
||||
|
||||
// Protocol
|
||||
@protocol NSSpeechRecognizerDelegate
|
||||
- (void) speechRecognizer: (NSSpeechRecognizer *)sender
|
||||
didRecognizeCommand: (NSString *)command;
|
||||
@end
|
||||
|
||||
APPKIT_EXPORT NSString *GSSpeechRecognizerDidRecognizeWordNotification;
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -36,7 +36,7 @@ typedef enum
|
|||
NSSpeechImmediateBoundary = 0,
|
||||
NSSpeechWordBoundary,
|
||||
NSSpeechSentenceBoundary
|
||||
}
|
||||
}
|
||||
NSSpeechBoundary;
|
||||
|
||||
// forward declarations...
|
||||
|
@ -184,3 +184,4 @@ extern NSString *NSSpeechDictionaryEntryPhonemes;
|
|||
@end
|
||||
|
||||
#endif // _GNUstep_H_NSSpeechSynthesizer
|
||||
|
||||
|
|
4
MISSING
4
MISSING
|
@ -12,7 +12,6 @@ MISSING HEADERS
|
|||
> NSCollectionViewGridLayout.h
|
||||
> NSCollectionViewLayout.h
|
||||
> NSCollectionViewTransitionLayout.h
|
||||
> NSColorSampler.h
|
||||
> NSDictionaryController.h
|
||||
> NSDiffableDataSource.h
|
||||
> NSDraggingItem.h
|
||||
|
@ -40,7 +39,6 @@ MISSING HEADERS
|
|||
> NSPressureConfiguration.h
|
||||
> NSSharingServicePickerToolbarItem.h
|
||||
> NSSliderAccessory.h
|
||||
> NSSpeechRecognizer.h
|
||||
> NSSplitViewController.h
|
||||
> NSSplitViewItem.h
|
||||
> NSStackView.h
|
||||
|
@ -76,6 +74,8 @@ Completed
|
|||
> NSDataAsset.h
|
||||
> NSTouch.h
|
||||
> NSTouchBar.h
|
||||
> NSSpeechRecognizer.h
|
||||
> NSColorSampler.h
|
||||
|
||||
Obsolete
|
||||
---
|
||||
|
|
|
@ -66,9 +66,9 @@ ADDITIONAL_CPPFLAGS += $(RUNTIME_DEFINE) $(GUI_DEFINE) $(BACKEND_DEFINE)
|
|||
ADDITIONAL_LIB_DIRS += -L$(GNUSTEP_OBJ_DIR)
|
||||
ifeq ($(GUI_LIB), gnu)
|
||||
ADDITIONAL_LIB_DIRS += -L../Source/$(GNUSTEP_OBJ_DIR)
|
||||
ADDITIONAL_INCLUDE_DIRS = -I../Headers/Additions -I../Headers
|
||||
ADDITIONAL_INCLUDE_DIRS += -I../Headers/Additions -I../Headers
|
||||
else
|
||||
ADDITIONAL_INCLUDE_DIRS = -I../Headers/Additions
|
||||
ADDITIONAL_INCLUDE_DIRS += -I../Headers/Additions
|
||||
endif
|
||||
|
||||
ADDITIONAL_OBJC_FLAGS += $(BACKEND_DEFINE)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
Copyright (C) 2003 Free Software Foundation, Inc.
|
||||
|
||||
Author: Serg Stoyan <stoyan@on.com.ua>
|
||||
Author: Sergii Stoian <stoyan255@gmail.com>
|
||||
Date: Mar 2003
|
||||
|
||||
This file is part of the GNUstep GUI Library.
|
||||
|
@ -41,6 +41,7 @@
|
|||
#import "AppKit/NSStringDrawing.h"
|
||||
#import "AppKit/NSView.h"
|
||||
#import "AppKit/NSWindow.h"
|
||||
#import "AppKit/NSScreen.h"
|
||||
|
||||
#import "GNUstepGUI/GSTitleView.h"
|
||||
#import "GNUstepGUI/GSTheme.h"
|
||||
|
@ -238,9 +239,32 @@
|
|||
NSDate *theDistantFuture = [NSDate distantFuture];
|
||||
NSPoint startWindowOrigin;
|
||||
NSPoint endWindowOrigin;
|
||||
NSRect screenFrame = NSZeroRect;
|
||||
CGFloat leftLimit = -1.0;
|
||||
CGFloat topLimit = -1.0 ;
|
||||
CGFloat rightLimit = -1.0;
|
||||
CGFloat bottomLimit = 0.0;
|
||||
|
||||
NSDebugLLog (@"NSMenu", @"Mouse down in title!");
|
||||
|
||||
// Define move constrains for menu
|
||||
if (_ownedByMenu)
|
||||
{
|
||||
NSRect windowFrame;
|
||||
NSScreen *screen;
|
||||
|
||||
if (_window && (screen = [_window screen]))
|
||||
{
|
||||
windowFrame = [_window frame];
|
||||
screenFrame = [screen frame];
|
||||
leftLimit = screenFrame.origin.x;
|
||||
topLimit = NSMaxY(screenFrame) - windowFrame.size.height;
|
||||
rightLimit = NSMaxX(screenFrame) - windowFrame.size.width;
|
||||
bottomLimit = screenFrame.origin.y -
|
||||
(windowFrame.size.height - [self frame].size.height);
|
||||
}
|
||||
}
|
||||
|
||||
// Remember start position of window
|
||||
startWindowOrigin = [_window frame].origin;
|
||||
|
||||
|
@ -275,6 +299,19 @@
|
|||
origin.y += (location.y - lastLocation.y);
|
||||
if (_ownedByMenu)
|
||||
{
|
||||
if (screenFrame.size.width > 0 && screenFrame.size.height > 0)
|
||||
{
|
||||
if (origin.x <= leftLimit)
|
||||
origin.x = leftLimit;
|
||||
else if (origin.x >= rightLimit)
|
||||
origin.x = rightLimit;
|
||||
|
||||
if (origin.y >= topLimit)
|
||||
origin.y = topLimit;
|
||||
else if (origin.y <= bottomLimit)
|
||||
origin.y = bottomLimit;
|
||||
}
|
||||
|
||||
[_owner nestedSetFrameOrigin: origin];
|
||||
}
|
||||
else
|
||||
|
|
|
@ -113,118 +113,6 @@ static NSString *ApplicationClass = nil;
|
|||
|
||||
@end
|
||||
|
||||
@interface IBActionConnection5 : IBActionConnection
|
||||
{
|
||||
NSString *trigger;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation IBActionConnection5
|
||||
|
||||
- (instancetype) initWithCoder: (NSCoder *)coder
|
||||
{
|
||||
self = [super initWithCoder: coder];
|
||||
if (self)
|
||||
{
|
||||
trigger = nil;
|
||||
|
||||
if ([coder allowsKeyedCoding])
|
||||
{
|
||||
// label and source string tags have changed for XIB5...
|
||||
ASSIGN(label, [coder decodeObjectForKey: @"selector"]);
|
||||
ASSIGN(source, [coder decodeObjectForKey: @"target"]);
|
||||
// destination string tag is still the same (so far) and loaded
|
||||
// by base class...
|
||||
//ASSIGN(destination, [coder decodeObjectForKey: @"destination"]);
|
||||
|
||||
// Looks like the 'trigger' attribute should be used to override the
|
||||
// target/action setup method...
|
||||
if ([coder containsValueForKey: @"trigger"])
|
||||
ASSIGN(trigger, [coder decodeObjectForKey: @"trigger"]);
|
||||
}
|
||||
else
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"Can't decode %@ with %@.",NSStringFromClass([self class]),
|
||||
NSStringFromClass([coder class])];
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSString*) trigger
|
||||
{
|
||||
return trigger;
|
||||
}
|
||||
|
||||
- (void) establishConnection
|
||||
{
|
||||
if (trigger && [trigger length])
|
||||
{
|
||||
SEL sel = NSSelectorFromString(label);
|
||||
NSString *selName = [NSString stringWithFormat: @"set%@%@:",
|
||||
[[trigger substringToIndex: 1] uppercaseString],
|
||||
[trigger substringFromIndex: 1]];
|
||||
SEL trigsel = NSSelectorFromString(selName);
|
||||
|
||||
if (sel && trigsel && [destination respondsToSelector: trigsel])
|
||||
{
|
||||
NSWarnMLog(@"setting trigger %@ to selector %@", selName, label);
|
||||
//[destination setTarget: source]; // Not needed???
|
||||
[destination performSelector: trigsel withObject: (id)sel];
|
||||
}
|
||||
else if (!sel)
|
||||
{
|
||||
NSWarnMLog(@"label %@ does not correspond to any selector", label);
|
||||
}
|
||||
else if (!trigsel)
|
||||
{
|
||||
NSWarnMLog(@"trigger %@ does not correspond to any selector", trigger);
|
||||
}
|
||||
else
|
||||
{
|
||||
NSWarnMLog(@"destination class (%@) does not respond to trigger selector %@",
|
||||
NSStringFromClass([destination class]), selName);
|
||||
}
|
||||
|
||||
// PREMATURE RETURN...
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise invoke the super class' method...
|
||||
[super establishConnection];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface IBOutletConnection5 : IBOutletConnection
|
||||
@end
|
||||
|
||||
@implementation IBOutletConnection5
|
||||
|
||||
- (instancetype) initWithCoder: (NSCoder *)coder
|
||||
{
|
||||
self = [super initWithCoder: coder];
|
||||
if (self)
|
||||
{
|
||||
if ([coder allowsKeyedCoding])
|
||||
{
|
||||
// label string tag has changed for XIB5...
|
||||
ASSIGN(label, [coder decodeObjectForKey: @"property"]);
|
||||
// destination and source string tags are still the same (so far) and loaded
|
||||
// by base class...
|
||||
}
|
||||
else
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"Can't decode %@ with %@.",NSStringFromClass([self class]),
|
||||
NSStringFromClass([coder class])];
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface IBUserDefinedRuntimeAttribute5 : IBUserDefinedRuntimeAttribute
|
||||
@end
|
||||
|
@ -313,8 +201,8 @@ static NSArray *XmlBoolDefaultYes = nil;
|
|||
@"NSSegmentItem", @"segment",
|
||||
@"NSCell", @"customCell",
|
||||
@"NSCustomObject5", @"customObject",
|
||||
@"IBOutletConnection5", @"outlet",
|
||||
@"IBActionConnection5", @"action",
|
||||
@"IBOutletConnection", @"outlet",
|
||||
@"IBActionConnection", @"action",
|
||||
@"NSNibBindingConnector", @"binding",
|
||||
@"NSWindowTemplate", @"window",
|
||||
@"NSView", @"tableCellView",
|
||||
|
@ -2401,7 +2289,8 @@ didStartElement: (NSString*)elementName
|
|||
mask.flags.highlighted = [[attributes objectForKey: @"highlighted"] boolValue];
|
||||
mask.flags.disabled = ([attributes objectForKey: @"enabled"] ?
|
||||
[[attributes objectForKey: @"enabled"] boolValue] == NO : NO);
|
||||
mask.flags.editable = [[attributes objectForKey: @"editable"] boolValue];
|
||||
mask.flags.editable = ([attributes objectForKey: @"editable"] ?
|
||||
[[attributes objectForKey: @"editable"] boolValue] : YES);
|
||||
mask.flags.vCentered = [[attributes objectForKey: @"alignment"] isEqualToString: @"center"];
|
||||
mask.flags.hCentered = [[attributes objectForKey: @"alignment"] isEqualToString: @"center"];
|
||||
mask.flags.bordered = [[borderStyle lowercaseString] containsString: @"border"];
|
||||
|
@ -3121,7 +3010,7 @@ didStartElement: (NSString*)elementName
|
|||
return flag;
|
||||
}
|
||||
|
||||
- (NSPoint) decodePointForKey:(NSString *)key
|
||||
- (NSPoint) decodePointForKey: (NSString *)key
|
||||
{
|
||||
NSPoint point = NSZeroPoint;
|
||||
|
||||
|
|
|
@ -421,18 +421,117 @@
|
|||
|
||||
@implementation IBActionConnection
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
DESTROY(trigger);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (instancetype) initWithCoder: (NSCoder *)coder
|
||||
{
|
||||
self = [super initWithCoder: coder];
|
||||
if (self)
|
||||
{
|
||||
if ([coder allowsKeyedCoding])
|
||||
{
|
||||
// label and source string tags have changed for XIB5...
|
||||
if ([coder containsValueForKey: @"selector"])
|
||||
{
|
||||
ASSIGN(label, [coder decodeObjectForKey: @"selector"]);
|
||||
}
|
||||
if ([coder containsValueForKey: @"target"])
|
||||
{
|
||||
ASSIGN(source, [coder decodeObjectForKey: @"target"]);
|
||||
}
|
||||
|
||||
// Looks like the 'trigger' attribute should be used to override the
|
||||
// action setup method...
|
||||
if ([coder containsValueForKey: @"trigger"])
|
||||
{
|
||||
ASSIGN(trigger, [coder decodeObjectForKey: @"trigger"]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"Can't decode %@ with %@.", NSStringFromClass([self class]),
|
||||
NSStringFromClass([coder class])];
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSString*) trigger
|
||||
{
|
||||
return trigger;
|
||||
}
|
||||
|
||||
- (void) establishConnection
|
||||
{
|
||||
SEL sel = NSSelectorFromString(label);
|
||||
|
||||
[destination setTarget: source];
|
||||
[destination setAction: sel];
|
||||
|
||||
if (trigger && [trigger length])
|
||||
{
|
||||
NSString *selName = [NSString stringWithFormat: @"set%@%@:",
|
||||
[[trigger substringToIndex: 1] uppercaseString],
|
||||
[trigger substringFromIndex: 1]];
|
||||
SEL trigsel = NSSelectorFromString(selName);
|
||||
|
||||
if (sel && trigsel && [destination respondsToSelector: trigsel])
|
||||
{
|
||||
NSWarnMLog(@"setting trigger %@ to selector %@", selName, label);
|
||||
[destination performSelector: trigsel withObject: (id)sel];
|
||||
}
|
||||
else if (!sel)
|
||||
{
|
||||
NSWarnMLog(@"label %@ does not correspond to any selector", label);
|
||||
}
|
||||
else if (!trigsel)
|
||||
{
|
||||
NSWarnMLog(@"trigger %@ does not correspond to any selector", trigger);
|
||||
}
|
||||
else
|
||||
{
|
||||
NSWarnMLog(@"destination class (%@) does not respond to trigger selector %@",
|
||||
NSStringFromClass([destination class]), selName);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise invoke the normal method...
|
||||
[destination setAction: sel];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation IBOutletConnection
|
||||
|
||||
- (instancetype) initWithCoder: (NSCoder *)coder
|
||||
{
|
||||
self = [super initWithCoder: coder];
|
||||
if (self)
|
||||
{
|
||||
if ([coder allowsKeyedCoding])
|
||||
{
|
||||
// label string tag has changed for XIB5...
|
||||
if ([coder containsValueForKey: @"property"])
|
||||
{
|
||||
ASSIGN(label, [coder decodeObjectForKey: @"property"]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"Can't decode %@ with %@.", NSStringFromClass([self class]),
|
||||
NSStringFromClass([coder class])];
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) establishConnection
|
||||
{
|
||||
NS_DURING
|
||||
|
@ -866,10 +965,10 @@
|
|||
|
||||
- (NSString*) description
|
||||
{
|
||||
return [NSString stringWithFormat:
|
||||
@"%@ - sourceID: %@: maxID: %@: objectRecords: %@: flattenedProperties: %@: connectionRecords: %@: ",
|
||||
[super description], sourceID, maxID, objectRecords,
|
||||
flattenedProperties, connectionRecords];
|
||||
return [NSString stringWithFormat: @"%@ - sourceID: %@: maxID: %d:"
|
||||
@" objectRecords: %@: flattenedProperties: %@: connectionRecords: %@: ",
|
||||
[super description], sourceID, maxID,
|
||||
objectRecords, flattenedProperties, connectionRecords];
|
||||
}
|
||||
|
||||
- (NSEnumerator*) connectionRecordEnumerator
|
||||
|
|
|
@ -3896,6 +3896,7 @@ struct _DelegateWrapper
|
|||
|
||||
iconContentRect = GSGetIconFrame(_app_icon_window);
|
||||
iconFrame = [_app_icon_window frameRectForContentRect: iconContentRect];
|
||||
iconFrame.origin = [[NSScreen mainScreen] frame].origin;
|
||||
iconViewFrame = NSMakeRect(0, 0,
|
||||
iconContentRect.size.width, iconContentRect.size.height);
|
||||
[_app_icon_window setFrame: iconFrame display: YES];
|
||||
|
|
158
Source/NSColorSampler.m
Normal file
158
Source/NSColorSampler.m
Normal file
|
@ -0,0 +1,158 @@
|
|||
/* Implementation of class NSColorSampler
|
||||
Copyright (C) 2019 Free Software Foundation, Inc.
|
||||
|
||||
By: Gregory John Casamento
|
||||
Date: Thu Mar 12 03:11:27 EDT 2020
|
||||
|
||||
This file is part of the GNUstep Library.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110 USA.
|
||||
*/
|
||||
|
||||
#import <Foundation/NSGeometry.h>
|
||||
#import <Foundation/NSDate.h>
|
||||
#import <Foundation/NSException.h>
|
||||
#import <Foundation/NSAutoreleasePool.h>
|
||||
#import <Foundation/NSLock.h>
|
||||
|
||||
#import <AppKit/NSApplication.h>
|
||||
#import <AppKit/NSBitmapImageRep.h>
|
||||
#import <AppKit/NSColorSampler.h>
|
||||
#import <AppKit/NSCursor.h>
|
||||
#import <AppKit/NSColor.h>
|
||||
#import <AppKit/NSEvent.h>
|
||||
#import <AppKit/NSImage.h>
|
||||
#import <AppKit/NSScreen.h>
|
||||
#import <AppKit/NSPanel.h>
|
||||
|
||||
#import <GNUstepGUI/GSDisplayServer.h>
|
||||
|
||||
static NSLock *_gs_gui_color_sampler_lock = nil;
|
||||
static NSColorSampler *_gs_gui_color_sampler = nil;
|
||||
|
||||
@interface NSWindow (private)
|
||||
- (void) _captureMouse: sender;
|
||||
- (void) _releaseMouse: sender;
|
||||
@end
|
||||
|
||||
@implementation NSColorSampler
|
||||
|
||||
+ (void) initialize
|
||||
{
|
||||
if (self == [NSColorSampler class])
|
||||
{
|
||||
// Initial version
|
||||
[self setVersion: 1];
|
||||
_gs_gui_color_sampler_lock = [NSLock new];
|
||||
}
|
||||
}
|
||||
|
||||
- (instancetype) init
|
||||
{
|
||||
if (_gs_gui_color_sampler == nil)
|
||||
{
|
||||
_gs_gui_color_sampler = self;
|
||||
}
|
||||
|
||||
if (self != _gs_gui_color_sampler)
|
||||
{
|
||||
RELEASE(self);
|
||||
return _gs_gui_color_sampler;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) showSamplerWithSelectionHandler: (GSColorSampleHandler)selectionHandler
|
||||
{
|
||||
NSEvent *currentEvent;
|
||||
NSCursor *cursor;
|
||||
NSRect contentRect = NSMakeRect(-1024,-1024,0,0);
|
||||
unsigned int style = NSTitledWindowMask | NSClosableWindowMask
|
||||
| NSResizableWindowMask | NSUtilityWindowMask;
|
||||
NSPanel *w = nil;
|
||||
NSColor *color = nil;
|
||||
|
||||
[_gs_gui_color_sampler_lock lock];
|
||||
|
||||
w = [[NSPanel alloc] initWithContentRect: contentRect
|
||||
styleMask: style
|
||||
backing: NSBackingStoreRetained
|
||||
defer: NO
|
||||
screen: nil];
|
||||
|
||||
[w setBecomesKeyOnlyIfNeeded: YES];
|
||||
[w makeKeyAndOrderFront: self];
|
||||
[w _captureMouse: self];
|
||||
|
||||
/**
|
||||
* There was code here to dynamically generate a magnifying glass
|
||||
* cursor with a magnified portion of the screenshot in it,
|
||||
* but changing the cursor rapidly on X seems to cause flicker,
|
||||
* so we just use a plain magnifying glass. (dynamic code is in r33543)
|
||||
*/
|
||||
cursor = [[NSCursor alloc] initWithImage: [NSImage imageNamed: @"MagnifyGlass"]
|
||||
hotSpot: NSMakePoint(12, 13)];
|
||||
AUTORELEASE(cursor);
|
||||
[cursor push];
|
||||
|
||||
NS_DURING
|
||||
{
|
||||
do
|
||||
{
|
||||
NSPoint mouseLoc;
|
||||
NSImage *img;
|
||||
CREATE_AUTORELEASE_POOL(pool);
|
||||
|
||||
RELEASE(color);
|
||||
currentEvent = [NSApp nextEventMatchingMask: NSLeftMouseDownMask | NSLeftMouseUpMask | NSMouseMovedMask
|
||||
untilDate: [NSDate distantFuture]
|
||||
inMode: NSEventTrackingRunLoopMode
|
||||
dequeue: YES];
|
||||
|
||||
mouseLoc = [w convertBaseToScreen: [w mouseLocationOutsideOfEventStream]];
|
||||
|
||||
img = [GSCurrentServer() contentsOfScreen: [[w screen] screenNumber]
|
||||
inRect: NSMakeRect(mouseLoc.x, mouseLoc.y, 1, 1)];
|
||||
|
||||
if (nil != img)
|
||||
{
|
||||
NSBitmapImageRep *rep = (NSBitmapImageRep *)[img bestRepresentationForDevice: nil];
|
||||
color = [rep colorAtX: 0 y: 0];
|
||||
RETAIN(color);
|
||||
}
|
||||
[pool drain];
|
||||
} while ([currentEvent type] != NSLeftMouseUp &&
|
||||
[currentEvent type] != NSLeftMouseDown);
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
NSLog(@"Exception occurred in -[NSColorSampler showSamplerWithSelectionHandler:] : %@",
|
||||
localException);
|
||||
}
|
||||
NS_ENDHANDLER;
|
||||
|
||||
CALL_BLOCK(selectionHandler, color);
|
||||
RELEASE(color);
|
||||
[NSCursor pop];
|
||||
[w _releaseMouse: self];
|
||||
[w close];
|
||||
|
||||
[_gs_gui_color_sampler_lock unlock];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
@ -155,7 +155,7 @@
|
|||
{
|
||||
if ([aCoder allowsKeyedCoding])
|
||||
{
|
||||
[aCoder encodeObject: _attributes forKey: @"NSAttributes"];
|
||||
[aCoder encodeObject: _attributes forKey: @"NSFontDescriptorAttributes"];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -167,7 +167,7 @@
|
|||
{
|
||||
if ([aDecoder allowsKeyedCoding])
|
||||
{
|
||||
_attributes = RETAIN([aDecoder decodeObjectForKey: @"NSAttributes"]);
|
||||
_attributes = RETAIN([aDecoder decodeObjectForKey: @"NSFontDescriptorAttributes"]);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -470,8 +470,10 @@ static BOOL menuBarVisible = YES;
|
|||
|
||||
if (_menu.horizontal == YES)
|
||||
{
|
||||
origin = NSMakePoint (0, [[NSScreen mainScreen] frame].size.height
|
||||
- [_aWindow frame].size.height);
|
||||
NSRect screenFrame = [[NSScreen mainScreen] frame];
|
||||
origin = NSMakePoint (0, screenFrame.size.height
|
||||
- [_aWindow frame].size.height);
|
||||
origin.y += screenFrame.origin.y;
|
||||
[_aWindow setFrameOrigin: origin];
|
||||
[_bWindow setFrameOrigin: origin];
|
||||
}
|
||||
|
@ -1801,6 +1803,23 @@ static BOOL menuBarVisible = YES;
|
|||
[[supermenu menuRepresentation] setHighlightedItemIndex: -1];
|
||||
supermenu->_attachedMenu = nil;
|
||||
}
|
||||
[nc addObserver: self
|
||||
selector: @selector(windowDidChangeScreen:)
|
||||
name: NSWindowDidBecomeKeyNotification
|
||||
object: nil];
|
||||
[nc addObserver: self
|
||||
selector: @selector(windowDidChangeScreen:)
|
||||
name: NSWindowDidChangeScreenNotification
|
||||
object: nil];
|
||||
}
|
||||
else
|
||||
{
|
||||
[nc removeObserver: self
|
||||
name: NSWindowDidBecomeKeyNotification
|
||||
object: nil];
|
||||
[nc removeObserver: self
|
||||
name: NSWindowDidChangeScreenNotification
|
||||
object: nil];
|
||||
}
|
||||
[_view update];
|
||||
}
|
||||
|
@ -1848,6 +1867,18 @@ static BOOL menuBarVisible = YES;
|
|||
[[GSTheme theme] updateAllWindowsWithMenu: [NSApp mainMenu]];
|
||||
}
|
||||
[self _showTornOffMenuIfAny: notification];
|
||||
|
||||
if ([NSApp mainMenu] == self)
|
||||
{
|
||||
[nc addObserver: self
|
||||
selector: @selector(windowDidChangeScreen:)
|
||||
name: NSWindowDidBecomeKeyNotification
|
||||
object: nil];
|
||||
[nc addObserver: self
|
||||
selector: @selector(windowDidChangeScreen:)
|
||||
name: NSWindowDidChangeScreenNotification
|
||||
object: nil];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) _showOnActivateApp: (NSNotification*)notification
|
||||
|
@ -1860,6 +1891,38 @@ static BOOL menuBarVisible = YES;
|
|||
}
|
||||
}
|
||||
|
||||
- (void) windowDidChangeScreen: (NSNotification*)notification
|
||||
{
|
||||
NSWindow *window = [notification object];
|
||||
NSRect frame;
|
||||
NSRect oldScreenFrame;
|
||||
NSRect newScreenFrame;
|
||||
CGFloat yOffset;
|
||||
|
||||
if ([window isKindOfClass: [NSPanel class]]
|
||||
|| window == _aWindow
|
||||
|| [window isKeyWindow] == NO
|
||||
|| [_aWindow screen] == [window screen]
|
||||
|| [_aWindow isVisible] == NO)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
oldScreenFrame = [[_aWindow screen] frame];
|
||||
newScreenFrame = [[window screen] frame];
|
||||
frame = [_aWindow frame];
|
||||
|
||||
// Keep left offset fixed
|
||||
frame.origin.x += newScreenFrame.origin.x - oldScreenFrame.origin.x;
|
||||
|
||||
// Keep top offset fixed
|
||||
yOffset = NSMaxY(oldScreenFrame) - NSMaxY(frame);
|
||||
frame.origin.y = NSMaxY(newScreenFrame) - yOffset - frame.size.height;
|
||||
|
||||
// setFrame: changes _screen value.
|
||||
[self nestedSetFrameOrigin: frame.origin];
|
||||
}
|
||||
|
||||
- (BOOL) isTransient
|
||||
{
|
||||
return _menu.transient;
|
||||
|
|
|
@ -60,12 +60,7 @@
|
|||
if (self == [NSScreen class])
|
||||
{
|
||||
[self setVersion: 1];
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserver: self
|
||||
selector: @selector(_resetScreens:)
|
||||
name: NSApplicationDidChangeScreenParametersNotification
|
||||
object: nil];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static NSMutableArray *screenArray = nil;
|
||||
|
@ -73,11 +68,6 @@ static NSMutableArray *screenArray = nil;
|
|||
/**
|
||||
* Resets the cached list of screens.
|
||||
*/
|
||||
+ (void) _resetScreens: (NSNotification*)notification
|
||||
{
|
||||
[self resetScreens];
|
||||
}
|
||||
|
||||
+ (void) resetScreens
|
||||
{
|
||||
DESTROY(screenArray);
|
||||
|
@ -132,6 +122,11 @@ static NSMutableArray *screenArray = nil;
|
|||
NSWindow *keyWindow;
|
||||
|
||||
keyWindow = [NSApp keyWindow];
|
||||
if (keyWindow == nil)
|
||||
{
|
||||
keyWindow = [[NSApp mainMenu] window];
|
||||
}
|
||||
|
||||
if (keyWindow != nil)
|
||||
{
|
||||
return [keyWindow screen];
|
||||
|
|
|
@ -8,16 +8,16 @@
|
|||
* This file is part of GNUstep.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110
|
||||
* USA.
|
||||
|
|
|
@ -8,16 +8,16 @@
|
|||
* This file is part of GNUstep.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* it under the terms of the Lesser GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
* Lesser GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* You should have received a copy of the Lesser GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110
|
||||
* USA.
|
||||
|
|
|
@ -23,8 +23,313 @@
|
|||
*/
|
||||
|
||||
#import <AppKit/NSSpeechRecognizer.h>
|
||||
#import <AppKit/NSApplication.h>
|
||||
#import <Foundation/NSDistantObject.h>
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSThread.h>
|
||||
#import <Foundation/NSError.h>
|
||||
#import <Foundation/NSConnection.h>
|
||||
#import <Foundation/NSDistributedNotificationCenter.h>
|
||||
#import <Foundation/NSDebug.h>
|
||||
#import <Foundation/NSUUID.h>
|
||||
#import "GSFastEnumeration.h"
|
||||
#import "AppKit/NSWorkspace.h"
|
||||
#import "AppKit/NSWindow.h"
|
||||
|
||||
@implementation NSSpeechRecognizer
|
||||
id _speechRecognitionServer = nil;
|
||||
BOOL _serverLaunchTested = NO;
|
||||
|
||||
#define SPEECH_RECOGNITION_SERVER @"GSSpeechRecognitionServer"
|
||||
|
||||
@interface NSObject (SpeechRecognitionServerPrivate)
|
||||
|
||||
- (void) addToBlockingRecognizers: (NSString *)s;
|
||||
- (void) removeFromBlockingRecognizers: (NSString *)s;
|
||||
- (BOOL) isBlocking: (NSString *)s;
|
||||
- (void) addClient;
|
||||
|
||||
@end
|
||||
|
||||
@implementation NSSpeechRecognizer
|
||||
|
||||
+ (void) initialize
|
||||
{
|
||||
if (self == [NSSpeechRecognizer class])
|
||||
{
|
||||
// Test for an existant server...
|
||||
_speechRecognitionServer =
|
||||
[NSConnection rootProxyForConnectionWithRegisteredName: SPEECH_RECOGNITION_SERVER
|
||||
host: nil];
|
||||
|
||||
// if none exists, start one. We will connect with it in init.
|
||||
if (nil == _speechRecognitionServer)
|
||||
{
|
||||
NSWorkspace *ws = [NSWorkspace sharedWorkspace];
|
||||
[ws launchApplication: SPEECH_RECOGNITION_SERVER
|
||||
showIcon: NO
|
||||
autolaunch: NO];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void) _restartServer
|
||||
{
|
||||
if (nil == _speechRecognitionServer && !_serverLaunchTested)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
|
||||
// Wait for up to five seconds for the server to launch, then give up.
|
||||
for (i = 0 ; i < 50 ; i++)
|
||||
{
|
||||
_speechRecognitionServer = [NSConnection
|
||||
rootProxyForConnectionWithRegisteredName: SPEECH_RECOGNITION_SERVER
|
||||
host: nil];
|
||||
RETAIN(_speechRecognitionServer);
|
||||
if (nil != _speechRecognitionServer)
|
||||
{
|
||||
NSDebugLog(@"Server found!!!");
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_DURING
|
||||
{
|
||||
NSWorkspace *ws = [NSWorkspace sharedWorkspace];
|
||||
[ws launchApplication: SPEECH_RECOGNITION_SERVER
|
||||
showIcon: NO
|
||||
autolaunch: NO];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
}
|
||||
NS_ENDHANDLER;
|
||||
}
|
||||
[NSThread sleepForTimeInterval: 0.1];
|
||||
}
|
||||
|
||||
// Set a flag so we don't bother waiting for the speech recognition server to
|
||||
// launch the next time if it didn't work this time.
|
||||
_serverLaunchTested = YES;
|
||||
}
|
||||
|
||||
if (_speechRecognitionServer == nil)
|
||||
{
|
||||
NSLog(@"Cannot restart speech recognition server.");
|
||||
}
|
||||
}
|
||||
|
||||
- (void) processNotification: (NSNotification *)note
|
||||
{
|
||||
NSString *word = (NSString *)[note object];
|
||||
NSDebugLog(@"Notified");
|
||||
if (_listensInForegroundOnly)
|
||||
{
|
||||
if (_appInForeground == NO)
|
||||
{
|
||||
NSDebugLog(@"Only in foreground..");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (_blocksOtherRecognizers)
|
||||
{
|
||||
NS_DURING
|
||||
{
|
||||
/*
|
||||
if ([_speechRecognitionServer isBlocking: [_uuid UUIDString]] == NO)
|
||||
{
|
||||
// If we are not a blocking recognizer, then we are blocked...
|
||||
NSDebugLog(@"Blocked...");
|
||||
return;
|
||||
}
|
||||
*/
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
NSLog(@"%@", localException);
|
||||
[self _restartServer];
|
||||
}
|
||||
NS_ENDHANDLER;
|
||||
}
|
||||
|
||||
word = [word lowercaseString];
|
||||
FOR_IN(NSString*, obj, _commands)
|
||||
{
|
||||
if ([[obj lowercaseString] isEqualToString: word])
|
||||
{
|
||||
[_delegate speechRecognizer: self
|
||||
didRecognizeCommand: word];
|
||||
}
|
||||
}
|
||||
END_FOR_IN(_commands);
|
||||
}
|
||||
|
||||
- (void) processAppStatusNotification: (NSNotification *)note
|
||||
{
|
||||
NSString *name = [note name];
|
||||
|
||||
if ([name isEqualToString: NSApplicationDidBecomeActiveNotification] ||
|
||||
[name isEqualToString: NSApplicationDidFinishLaunchingNotification] ||
|
||||
[name isEqualToString: NSWindowDidBecomeKeyNotification])
|
||||
{
|
||||
_appInForeground = YES;
|
||||
}
|
||||
else
|
||||
{
|
||||
_appInForeground = NO;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize
|
||||
- (instancetype) init
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserver: self
|
||||
selector: @selector(processAppStatusNotification:)
|
||||
name: NSApplicationDidFinishLaunchingNotification
|
||||
object: nil];
|
||||
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserver: self
|
||||
selector: @selector(processAppStatusNotification:)
|
||||
name: NSWindowDidBecomeKeyNotification
|
||||
object: nil];
|
||||
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserver: self
|
||||
selector: @selector(processAppStatusNotification:)
|
||||
name: NSApplicationDidBecomeActiveNotification
|
||||
object: nil];
|
||||
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserver: self
|
||||
selector: @selector(processAppStatusNotification:)
|
||||
name: NSApplicationDidResignActiveNotification
|
||||
object: nil];
|
||||
|
||||
_delegate = nil;
|
||||
_blocksOtherRecognizers = NO;
|
||||
_listensInForegroundOnly = YES;
|
||||
_appInForeground = YES;
|
||||
_uuid = [NSUUID UUID];
|
||||
|
||||
[self _restartServer];
|
||||
}
|
||||
|
||||
NS_DURING
|
||||
{
|
||||
[_speechRecognitionServer addClient]; // do this to update the client count;
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
NSLog(@"%@", localException);
|
||||
[self _restartServer];
|
||||
}
|
||||
NS_ENDHANDLER;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[[NSDistributedNotificationCenter defaultCenter] removeObserver: self];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver: self];
|
||||
_delegate = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
// Delegate
|
||||
- (id<NSSpeechRecognizerDelegate>) delegate
|
||||
{
|
||||
return _delegate;
|
||||
}
|
||||
|
||||
- (void) setDelegate: (id<NSSpeechRecognizerDelegate>)delegate
|
||||
{
|
||||
_delegate = delegate;
|
||||
}
|
||||
|
||||
// Configuring...
|
||||
- (NSArray *) commands
|
||||
{
|
||||
return _commands;
|
||||
}
|
||||
|
||||
- (void) setCommands: (NSArray *)commands
|
||||
{
|
||||
ASSIGNCOPY(_commands, commands);
|
||||
}
|
||||
|
||||
- (NSString *) displayCommandsTitle
|
||||
{
|
||||
return _displayCommandsTitle;
|
||||
}
|
||||
|
||||
- (void) setDisplayCommandsTitle: (NSString *)displayCommandsTitle
|
||||
{
|
||||
ASSIGNCOPY(_displayCommandsTitle, displayCommandsTitle);
|
||||
}
|
||||
|
||||
- (BOOL) listensInForegroundOnly
|
||||
{
|
||||
return _listensInForegroundOnly;
|
||||
}
|
||||
|
||||
- (void) setListensInForegroundOnly: (BOOL)listensInForegroundOnly
|
||||
{
|
||||
_listensInForegroundOnly = listensInForegroundOnly;
|
||||
}
|
||||
|
||||
- (BOOL) blocksOtherRecognizers
|
||||
{
|
||||
return _blocksOtherRecognizers;
|
||||
}
|
||||
|
||||
- (void) setBlocksOtherRecognizers: (BOOL)blocksOtherRecognizers
|
||||
{
|
||||
NS_DURING
|
||||
{
|
||||
if (blocksOtherRecognizers == YES)
|
||||
{
|
||||
[_speechRecognitionServer addToBlockingRecognizers: [_uuid UUIDString]];
|
||||
}
|
||||
else
|
||||
{
|
||||
[_speechRecognitionServer removeFromBlockingRecognizers: [_uuid UUIDString]];
|
||||
}
|
||||
_blocksOtherRecognizers = blocksOtherRecognizers;
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
NSLog(@"%@", localException);
|
||||
[self _restartServer];
|
||||
}
|
||||
NS_ENDHANDLER;
|
||||
}
|
||||
|
||||
// Listening
|
||||
- (void) startListening
|
||||
{
|
||||
// Start listening to the notification being sent by the server....
|
||||
[[NSDistributedNotificationCenter defaultCenter]
|
||||
addObserver: self
|
||||
selector: @selector(processNotification:)
|
||||
name: GSSpeechRecognizerDidRecognizeWordNotification
|
||||
object: nil];
|
||||
|
||||
}
|
||||
|
||||
- (void) stopListening
|
||||
{
|
||||
// Remove the observer for the notification....
|
||||
[[NSDistributedNotificationCenter defaultCenter]
|
||||
removeObserver: self
|
||||
name: GSSpeechRecognizerDidRecognizeWordNotification
|
||||
object: nil];
|
||||
}
|
||||
@end
|
||||
|
|
|
@ -102,58 +102,60 @@ static Class NSSpeechSynthesizerClass;
|
|||
- (NSSpeechSynthesizer*)newSynthesizer;
|
||||
@end
|
||||
|
||||
@implementation NSSpeechSynthesizer
|
||||
@implementation NSSpeechSynthesizer
|
||||
|
||||
- (id) initWithVoice: (NSString *)voice
|
||||
{
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
NSSpeechSynthesizerClass = [NSSpeechSynthesizer class];
|
||||
server = [[NSConnection rootProxyForConnectionWithRegisteredName: @"GSSpeechServer"
|
||||
host: nil] retain];
|
||||
if (nil == server)
|
||||
{
|
||||
NSWorkspace *ws = [NSWorkspace sharedWorkspace];
|
||||
[ws launchApplication: @"GSSpeechServer"
|
||||
showIcon: NO
|
||||
autolaunch: NO];
|
||||
}
|
||||
NSSpeechSynthesizerClass = [NSSpeechSynthesizer class];
|
||||
server = [[NSConnection rootProxyForConnectionWithRegisteredName: @"GSSpeechServer"
|
||||
host: nil] retain];
|
||||
if (nil == server)
|
||||
{
|
||||
NSWorkspace *ws = [NSWorkspace sharedWorkspace];
|
||||
[ws launchApplication: @"GSSpeechServer"
|
||||
showIcon: NO
|
||||
autolaunch: NO];
|
||||
}
|
||||
}
|
||||
|
||||
+ (BOOL)isAnyApplicationSpeaking
|
||||
{
|
||||
return [server isSpeaking];
|
||||
return [server isSpeaking];
|
||||
}
|
||||
|
||||
// Never really allocate one of these.
|
||||
+ (id)allocWithZone: (NSZone*)aZone
|
||||
{
|
||||
if (self == NSSpeechSynthesizerClass)
|
||||
{
|
||||
if (nil == server && !serverLaunchTested)
|
||||
{
|
||||
unsigned int i=0;
|
||||
// Wait for up to five seconds for the server to launch, then give up.
|
||||
for (i=0 ; i<50 ; i++)
|
||||
{
|
||||
server =
|
||||
[[NSConnection rootProxyForConnectionWithRegisteredName:
|
||||
@"GSSpeechServer"
|
||||
host: nil]
|
||||
retain];
|
||||
if (nil != server)
|
||||
{
|
||||
break;
|
||||
}
|
||||
[NSThread sleepForTimeInterval: 0.1];
|
||||
}
|
||||
// Set a flag so we don't bother waiting for the speech server to
|
||||
// launch the next time if it didn't work this time.
|
||||
serverLaunchTested = YES;
|
||||
}
|
||||
// If there is no server, this will return nil
|
||||
return [server newSynthesizer];
|
||||
}
|
||||
return [super allocWithZone: aZone];
|
||||
if (self == NSSpeechSynthesizerClass)
|
||||
{
|
||||
if (nil == server && !serverLaunchTested)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
// Wait for up to five seconds for the server to launch, then give up.
|
||||
for (i=0 ; i < 50 ; i++)
|
||||
{
|
||||
server = [NSConnection rootProxyForConnectionWithRegisteredName: @"GSSpeechServer"
|
||||
host: nil];
|
||||
RETAIN(server);
|
||||
if (nil != server)
|
||||
{
|
||||
break;
|
||||
}
|
||||
[NSThread sleepForTimeInterval: 0.1];
|
||||
}
|
||||
// Set a flag so we don't bother waiting for the speech server to
|
||||
// launch the next time if it didn't work this time.
|
||||
serverLaunchTested = YES;
|
||||
}
|
||||
// If there is no server, this will return nil
|
||||
return [server newSynthesizer];
|
||||
}
|
||||
return [super allocWithZone: aZone];
|
||||
}
|
||||
|
||||
// configuring speech synthesis
|
||||
|
|
|
@ -1106,6 +1106,10 @@ many times.
|
|||
selector: @selector(colorListChanged:)
|
||||
name: NSColorListDidChangeNotification
|
||||
object: nil];
|
||||
[nc addObserver: self
|
||||
selector: @selector(applicationDidChangeScreenParameters:)
|
||||
name: NSApplicationDidChangeScreenParametersNotification
|
||||
object: NSApp];
|
||||
|
||||
NSDebugLLog(@"NSWindow", @"NSWindow end of init\n");
|
||||
return self;
|
||||
|
@ -2083,16 +2087,12 @@ titleWithRepresentedFilename(NSString *representedFilename)
|
|||
|
||||
- (void) center
|
||||
{
|
||||
NSScreen *screen = [self screen];
|
||||
NSSize screenSize;
|
||||
NSPoint origin = _frame.origin;
|
||||
|
||||
if (screen == nil) {
|
||||
screen = [NSScreen mainScreen];
|
||||
}
|
||||
screenSize = [screen visibleFrame].size;
|
||||
origin.x = (screenSize.width - _frame.size.width) / 2;
|
||||
origin.y = (screenSize.height - _frame.size.height) / 2;
|
||||
NSRect screenFrame = [[NSScreen mainScreen] visibleFrame];
|
||||
NSSize screenSize = screenFrame.size;
|
||||
NSPoint origin = screenFrame.origin;
|
||||
|
||||
origin.x += (screenSize.width - _frame.size.width) / 2;
|
||||
origin.y += (screenSize.height - _frame.size.height) / 2;
|
||||
|
||||
[self setFrameOrigin: origin];
|
||||
}
|
||||
|
@ -2227,6 +2227,20 @@ titleWithRepresentedFilename(NSString *representedFilename)
|
|||
[self setFrame: r display: YES];
|
||||
}
|
||||
|
||||
- (void) _applyFrame: (NSRect )frameRect
|
||||
{
|
||||
if (_windowNum)
|
||||
{
|
||||
[GSServerForWindow(self) placewindow: frameRect : _windowNum];
|
||||
}
|
||||
else
|
||||
{
|
||||
_frame = frameRect;
|
||||
frameRect.origin = NSZeroPoint;
|
||||
[_wv setFrame: frameRect];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) setFrame: (NSRect)frameRect display: (BOOL)flag
|
||||
{
|
||||
if (_maximumSize.width > 0 && frameRect.size.width > _maximumSize.width)
|
||||
|
@ -2245,12 +2259,13 @@ titleWithRepresentedFilename(NSString *representedFilename)
|
|||
{
|
||||
frameRect.size.height = _minimumSize.height;
|
||||
}
|
||||
|
||||
|
||||
/* Windows need to be constrained when displayed or resized - but only
|
||||
titled windows are constrained */
|
||||
if (_styleMask & NSTitledWindowMask)
|
||||
{
|
||||
frameRect = [self constrainFrameRect: frameRect toScreen: [self screen]];
|
||||
frameRect = [self constrainFrameRect: frameRect
|
||||
toScreen: [self _screenForFrame: frameRect]];
|
||||
}
|
||||
|
||||
// If nothing changes, don't send it to the backend and don't redisplay
|
||||
|
@ -2264,14 +2279,7 @@ titleWithRepresentedFilename(NSString *representedFilename)
|
|||
* Now we can tell the graphics context to do the actual resizing.
|
||||
* We will recieve an event to tell us when the resize is done.
|
||||
*/
|
||||
if (_windowNum)
|
||||
[GSServerForWindow(self) placewindow: frameRect : _windowNum];
|
||||
else
|
||||
{
|
||||
_frame = frameRect;
|
||||
frameRect.origin = NSZeroPoint;
|
||||
[_wv setFrame: frameRect];
|
||||
}
|
||||
[self _applyFrame: frameRect];
|
||||
|
||||
if (flag)
|
||||
[self display];
|
||||
|
@ -2494,7 +2502,7 @@ titleWithRepresentedFilename(NSString *representedFilename)
|
|||
}
|
||||
|
||||
- (void) update
|
||||
{
|
||||
{
|
||||
[nc postNotificationName: NSWindowDidUpdateNotification object: self];
|
||||
}
|
||||
|
||||
|
@ -2701,6 +2709,54 @@ titleWithRepresentedFilename(NSString *representedFilename)
|
|||
return _screen;
|
||||
}
|
||||
|
||||
- (void) applicationDidChangeScreenParameters: (NSNotification *)aNotif
|
||||
{
|
||||
NSRect oldScreenFrame = [_screen frame];
|
||||
int screenNumber = [_screen screenNumber];
|
||||
NSRect newScreenFrame;
|
||||
NSRect newFrame;
|
||||
NSEnumerator *e;
|
||||
NSScreen *scr;
|
||||
|
||||
// We need to get new screen from renewed screen list because
|
||||
// [NSScreen mainScreen] returns NSScreen object of key window and that object
|
||||
// will never be released.
|
||||
e = [[NSScreen screens] objectEnumerator];
|
||||
while ((scr = [e nextObject]))
|
||||
{
|
||||
if ([scr screenNumber] == screenNumber)
|
||||
{
|
||||
ASSIGN(_screen, scr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Do not adjust frame for mini and appicon windows - it's a WM's job.
|
||||
if ([self isKindOfClass: [NSMiniWindow class]] || self == [NSApp iconWindow])
|
||||
return;
|
||||
|
||||
newScreenFrame = [_screen frame];
|
||||
|
||||
newFrame = _frame;
|
||||
// Screen Y origin change.
|
||||
newFrame.origin.y += newScreenFrame.origin.y - oldScreenFrame.origin.y;
|
||||
// Screen height change.
|
||||
newFrame.origin.y += newScreenFrame.size.height - oldScreenFrame.size.height;
|
||||
// Screen X origin change. Screen width change shouldn't affect our frame.
|
||||
newFrame.origin.x += newScreenFrame.origin.x - oldScreenFrame.origin.x;
|
||||
|
||||
/* Call backend's `placewindow::` directly because our origin in OpenStep
|
||||
coordinates might be unchanged and `setFrame:display:` has check
|
||||
for it. */
|
||||
[self _applyFrame: newFrame];
|
||||
[self display];
|
||||
|
||||
if (_autosaveName != nil)
|
||||
{
|
||||
[self saveFrameUsingName: _autosaveName];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) setDepthLimit: (NSWindowDepth)limit
|
||||
{
|
||||
if (limit == 0)
|
||||
|
@ -4127,16 +4183,25 @@ checkCursorRectanglesExited(NSView *theView, NSEvent *theEvent, NSPoint lastPoi
|
|||
switch (sub)
|
||||
{
|
||||
case GSAppKitWindowMoved:
|
||||
_frame.origin.x = (CGFloat)[theEvent data1];
|
||||
_frame.origin.y = (CGFloat)[theEvent data2];
|
||||
NSDebugLLog(@"Moving", @"Move event: %d %@",
|
||||
(int)_windowNum, NSStringFromPoint(_frame.origin));
|
||||
if (_autosaveName != nil)
|
||||
{
|
||||
[self saveFrameUsingName: _autosaveName];
|
||||
}
|
||||
[nc postNotificationName: NSWindowDidMoveNotification
|
||||
object: self];
|
||||
{
|
||||
NSScreen *oldScreen = _screen;
|
||||
|
||||
_frame.origin.x = (CGFloat)[theEvent data1];
|
||||
_frame.origin.y = (CGFloat)[theEvent data2];
|
||||
NSDebugLLog(@"Moving", @"Move event: %d %@",
|
||||
(int)_windowNum, NSStringFromPoint(_frame.origin));
|
||||
if (_autosaveName != nil)
|
||||
{
|
||||
[self saveFrameUsingName: _autosaveName];
|
||||
}
|
||||
[nc postNotificationName: NSWindowDidMoveNotification
|
||||
object: self];
|
||||
if ([self screen] != oldScreen)
|
||||
{
|
||||
[nc postNotificationName: NSWindowDidChangeScreenNotification
|
||||
object: self];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case GSAppKitWindowResized:
|
||||
|
@ -4918,16 +4983,6 @@ current key view.<br />
|
|||
* the window could be placed (ie a rectangle excluding the dock).
|
||||
*/
|
||||
screen = [self _screenForFrame: fRect];
|
||||
|
||||
// Check whether a portion is showing somewhere...
|
||||
if (screen == nil)
|
||||
{
|
||||
// If the window doesn't show up on any screen then we need
|
||||
// to move it so it can be seen and assign it to the main
|
||||
// screen...
|
||||
screen = [NSScreen mainScreen];
|
||||
NSDebugLLog(@"NSWindow", @"%s: re-assigning to main screen\n", __PRETTY_FUNCTION__);
|
||||
}
|
||||
nRect = [screen visibleFrame];
|
||||
|
||||
/*
|
||||
|
@ -4979,9 +5034,6 @@ current key view.<br />
|
|||
}
|
||||
}
|
||||
|
||||
// Make sure we are using the new screen we are applying to...
|
||||
ASSIGN(_screen, screen);
|
||||
|
||||
/*
|
||||
* Set frame.
|
||||
*/
|
||||
|
|
|
@ -812,6 +812,10 @@ const NSAppearanceName NSAppearanceNameAccessibilityHighContrastVibrantDark =
|
|||
@"NSAppearanceNameAccessibilityHighContrastVibrantDark";
|
||||
const NSAppearanceName NSAppearanceNameLightContent = @"NSAppearanceNameLightContent";
|
||||
|
||||
// Speech recognition...
|
||||
const NSString *GSSpeechRecognizerDidRecognizeWordNotification = @"GSSpeechRecognizerDidRecognizeWordNotification";
|
||||
|
||||
|
||||
extern void __objc_gui_force_linking (void);
|
||||
|
||||
void
|
||||
|
|
|
@ -28,7 +28,7 @@ include ../config.make
|
|||
|
||||
include ../Version
|
||||
|
||||
SUBPROJECTS = $(BUILD_SPEECH) $(BUILD_SOUND)
|
||||
SUBPROJECTS = $(BUILD_SPEECH) $(BUILD_SOUND) $(BUILD_SPEECH_RECOGNIZER)
|
||||
TOOL_NAME = make_services set_show_service gopen gclose gcloseall
|
||||
SERVICE_NAME = GSspell
|
||||
|
||||
|
|
|
@ -8,114 +8,119 @@ cst_voice *register_cmu_us_kal16();
|
|||
* for resource-constrained platforms.
|
||||
*/
|
||||
@interface FliteSpeechEngine : GSSpeechEngine {
|
||||
/** The audio device used for sound output. */
|
||||
cst_audiodev *ad;
|
||||
/** The current voice. Only one supported at the moment. */
|
||||
cst_voice *v;
|
||||
/** Flag set to tell the playback thread to exit. */
|
||||
volatile BOOL shouldEndSpeaking;
|
||||
/** Flag indicating whether the engine is currently speaking. */
|
||||
volatile BOOL isSpeaking;
|
||||
/** The audio device used for sound output. */
|
||||
cst_audiodev *ad;
|
||||
/** The current voice. Only one supported at the moment. */
|
||||
cst_voice *v;
|
||||
/** Flag set to tell the playback thread to exit. */
|
||||
volatile BOOL shouldEndSpeaking;
|
||||
/** Flag indicating whether the engine is currently speaking. */
|
||||
volatile BOOL isSpeaking;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation FliteSpeechEngine
|
||||
+ (void)initialize
|
||||
{
|
||||
flite_init();
|
||||
|
||||
flite_init();
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if (nil == (self = [super init])) { return nil; }
|
||||
|
||||
// Only one voice supported by flite unless others are compiled in.
|
||||
v = register_cmu_us_kal16();
|
||||
if (NULL == v)
|
||||
{
|
||||
[self release];
|
||||
return nil;
|
||||
}
|
||||
|
||||
// Each wave should be the same format.
|
||||
cst_wave *w = flite_text_to_wave("test", v);
|
||||
ad = audio_open(w->sample_rate, w->num_channels, CST_AUDIO_LINEAR16);
|
||||
delete_wave(w);
|
||||
if (NULL == ad)
|
||||
{
|
||||
[self release];
|
||||
return nil;
|
||||
}
|
||||
return self;
|
||||
if (nil == (self = [super init])) { return nil; }
|
||||
|
||||
// Only one voice supported by flite unless others are compiled in.
|
||||
v = register_cmu_us_kal16();
|
||||
if (NULL == v)
|
||||
{
|
||||
[self release];
|
||||
return nil;
|
||||
}
|
||||
|
||||
// Each wave should be the same format.
|
||||
cst_wave *w = flite_text_to_wave("test", v);
|
||||
ad = audio_open(w->sample_rate, w->num_channels, CST_AUDIO_LINEAR16);
|
||||
delete_wave(w);
|
||||
if (NULL == ad)
|
||||
{
|
||||
[self release];
|
||||
return nil;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)sayString: (NSArray*)args
|
||||
{
|
||||
id pool = [NSAutoreleasePool new];
|
||||
NSString *aString = [args objectAtIndex: 0];
|
||||
int i,n,r;
|
||||
int num_shorts;
|
||||
BOOL didFinish = YES;
|
||||
cst_wave *w = flite_text_to_wave([aString UTF8String], v);
|
||||
|
||||
num_shorts = w->num_samples * w->num_channels;
|
||||
for (i=0; i < num_shorts; i += r/2)
|
||||
{
|
||||
if (num_shorts > i+CST_AUDIOBUFFSIZE)
|
||||
{
|
||||
n = CST_AUDIOBUFFSIZE;
|
||||
}
|
||||
else
|
||||
{
|
||||
n = num_shorts-i;
|
||||
}
|
||||
r = audio_write(ad, &w->samples[i], n*2);
|
||||
if (shouldEndSpeaking)
|
||||
{
|
||||
didFinish = NO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
isSpeaking = NO;
|
||||
NS_DURING
|
||||
[[args objectAtIndex: 1] didFinishSpeaking: didFinish];
|
||||
NS_HANDLER
|
||||
NS_ENDHANDLER
|
||||
[args release];
|
||||
[pool release];
|
||||
delete_wave(w);
|
||||
id pool = [NSAutoreleasePool new];
|
||||
NSString *aString = [args objectAtIndex: 0];
|
||||
int i,n,r;
|
||||
int num_shorts;
|
||||
BOOL didFinish = YES;
|
||||
cst_wave *w = flite_text_to_wave([aString UTF8String], v);
|
||||
|
||||
num_shorts = w->num_samples * w->num_channels;
|
||||
for (i=0; i < num_shorts; i += r/2)
|
||||
{
|
||||
if (num_shorts > i+CST_AUDIOBUFFSIZE)
|
||||
{
|
||||
n = CST_AUDIOBUFFSIZE;
|
||||
}
|
||||
else
|
||||
{
|
||||
n = num_shorts-i;
|
||||
}
|
||||
r = audio_write(ad, &w->samples[i], n*2);
|
||||
if (shouldEndSpeaking)
|
||||
{
|
||||
didFinish = NO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
isSpeaking = NO;
|
||||
NS_DURING
|
||||
[[args objectAtIndex: 1] didFinishSpeaking: didFinish];
|
||||
NS_HANDLER
|
||||
NS_ENDHANDLER;
|
||||
[args release];
|
||||
[pool release];
|
||||
delete_wave(w);
|
||||
}
|
||||
|
||||
- (void)startSpeaking: (NSString*)aString notifyWhenDone: (id)aDelegate
|
||||
{
|
||||
[[[aDelegate delegate] connectionForProxy] enableMultipleThreads];
|
||||
NSArray *arg = [[NSArray alloc] initWithObjects: aString, aDelegate, nil];
|
||||
shouldEndSpeaking = NO;
|
||||
isSpeaking = YES;
|
||||
[NSThread detachNewThreadSelector: @selector(sayString:)
|
||||
toTarget: self
|
||||
withObject: arg];
|
||||
|
||||
[[[aDelegate delegate] connectionForProxy] enableMultipleThreads];
|
||||
NSArray *arg = [[NSArray alloc] initWithObjects: aString, aDelegate, nil];
|
||||
shouldEndSpeaking = NO;
|
||||
isSpeaking = YES;
|
||||
[NSThread detachNewThreadSelector: @selector(sayString:)
|
||||
toTarget: self
|
||||
withObject: arg];
|
||||
|
||||
}
|
||||
|
||||
- (BOOL)isSpeaking
|
||||
{
|
||||
return isSpeaking;
|
||||
return isSpeaking;
|
||||
}
|
||||
|
||||
- (void)stopSpeaking
|
||||
{
|
||||
shouldEndSpeaking = YES;
|
||||
// Spin until the other thread has died.
|
||||
while (isSpeaking) {}
|
||||
shouldEndSpeaking = YES;
|
||||
// Spin until the other thread has died.
|
||||
while (isSpeaking) {}
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[self stopSpeaking];
|
||||
audio_close(ad);
|
||||
[super dealloc];
|
||||
[self stopSpeaking];
|
||||
audio_close(ad);
|
||||
[super dealloc];
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation GSSpeechEngine (Flite)
|
||||
+ (GSSpeechEngine*)defaultSpeechEngine
|
||||
{
|
||||
return [[[FliteSpeechEngine alloc] init] autorelease];
|
||||
return [[[FliteSpeechEngine alloc] init] autorelease];
|
||||
}
|
||||
@end
|
||||
|
|
|
@ -8,65 +8,80 @@ static GSSpeechServer *sharedInstance;
|
|||
@implementation GSSpeechServer
|
||||
+ (void)initialize
|
||||
{
|
||||
sharedInstance = [self new];
|
||||
sharedInstance = [self new];
|
||||
}
|
||||
|
||||
+ (void)start
|
||||
{
|
||||
NSConnection *connection = [NSConnection defaultConnection];
|
||||
[connection setRootObject: sharedInstance];
|
||||
if (NO == [connection registerName: @"GSSpeechServer"])
|
||||
{
|
||||
return;
|
||||
}
|
||||
[[NSRunLoop currentRunLoop] run];
|
||||
NSConnection *connection = [NSConnection defaultConnection];
|
||||
[connection setRootObject: sharedInstance];
|
||||
if (NO == [connection registerName: @"GSSpeechServer"])
|
||||
{
|
||||
return;
|
||||
}
|
||||
[[NSRunLoop currentRunLoop] run];
|
||||
}
|
||||
|
||||
+ (id)sharedServer
|
||||
{
|
||||
return sharedInstance;
|
||||
return sharedInstance;
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if (nil == (self = [super init])) { return nil; }
|
||||
engine = [GSSpeechEngine defaultSpeechEngine];
|
||||
if (nil == engine)
|
||||
{
|
||||
[self release];
|
||||
return nil;
|
||||
}
|
||||
return self;
|
||||
if (nil == (self = [super init]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
engine = [GSSpeechEngine defaultSpeechEngine];
|
||||
if (nil == engine)
|
||||
{
|
||||
[self release];
|
||||
return nil;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)newSynthesizer
|
||||
{
|
||||
return [[GSSpeechSynthesizer new] autorelease];
|
||||
return [[GSSpeechSynthesizer new] autorelease];
|
||||
}
|
||||
|
||||
- (BOOL)startSpeakingString: (NSString*)aString notifyWhenDone: (id)client
|
||||
{
|
||||
[engine stopSpeaking];
|
||||
[engine startSpeaking: aString notifyWhenDone: client];
|
||||
return YES;
|
||||
[engine stopSpeaking];
|
||||
[engine startSpeaking: aString notifyWhenDone: client];
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)stopSpeaking
|
||||
{
|
||||
[engine stopSpeaking];
|
||||
[engine stopSpeaking];
|
||||
}
|
||||
|
||||
- (BOOL)isSpeaking
|
||||
{
|
||||
return [engine isSpeaking];
|
||||
return [engine isSpeaking];
|
||||
}
|
||||
|
||||
- (NSArray*)voices
|
||||
{
|
||||
return [engine voices];
|
||||
return [engine voices];
|
||||
}
|
||||
|
||||
- (oneway void)setVoice: (NSString*)aVoice
|
||||
{
|
||||
[engine setVoice: aVoice];
|
||||
[engine setVoice: aVoice];
|
||||
}
|
||||
|
||||
- (NSString*)voice
|
||||
{
|
||||
return [engine voice];
|
||||
return [engine voice];
|
||||
}
|
||||
|
||||
- (NSString*)defaultVoice
|
||||
{
|
||||
return [engine defaultVoice];
|
||||
return [engine defaultVoice];
|
||||
}
|
||||
@end
|
||||
|
|
26
Tools/speech_recognizer/GNUmakefile
Normal file
26
Tools/speech_recognizer/GNUmakefile
Normal file
|
@ -0,0 +1,26 @@
|
|||
include $(GNUSTEP_MAKEFILES)/common.make
|
||||
include ../../config.make
|
||||
|
||||
VERSION = 0.1
|
||||
|
||||
# This is an app not a tool because, eventually, it will present the user
|
||||
# interface for the GUI part of the speech engine.
|
||||
APP_NAME = GSSpeechRecognitionServer
|
||||
|
||||
GSSpeechRecognitionServer_LANGUAGES = English
|
||||
|
||||
GSSpeechRecognitionServer_OBJC_FILES = \
|
||||
GSSpeechRecognitionEngine.m \
|
||||
GSSpeechRecognitionServer.m \
|
||||
main.m
|
||||
|
||||
# Add includes and link dirs....
|
||||
GSSpeechRecognitionServer_OBJC_FILES += $(RECOGNIZER_ENGINE_CLASS)
|
||||
GSSpeechRecognitionServer_INCLUDE_DIRS += $(RECOGNIZER_BASE_CFLAGS) \
|
||||
-I../../Headers \
|
||||
-I../../Headers/Additions
|
||||
GSSpeechRecognitionServer_LIB_DIRS += -L../../Source/$(GNUSTEP_OBJ_DIR) \
|
||||
-L/usr/local/lib -lgnustep-gui \
|
||||
$(RECOGNIZER_BASE_LIBS)
|
||||
|
||||
include $(GNUSTEP_MAKEFILES)/application.make
|
49
Tools/speech_recognizer/GSSpeechRecognitionEngine.h
Normal file
49
Tools/speech_recognizer/GSSpeechRecognitionEngine.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
/* Interface of class GSSpeechRecognitionEngine
|
||||
Copyright (C) 2019 Free Software Foundation, Inc.
|
||||
|
||||
By: Gregory John Casamento
|
||||
Date: Fri Dec 6 04:55:59 EST 2019
|
||||
|
||||
This file is part of the GNUstep Library.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110 USA.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <AppKit/NSSpeechRecognizer.h>
|
||||
|
||||
/**
|
||||
* GSSpeechRecognitionEngine is an abstract speech server. One concrete subclass should
|
||||
* be implemented for each speech recognition engine. Currently, only one may be compiled
|
||||
* into the speech recognition server at any given time. This limitation may be removed
|
||||
* in future if pluggable speech engines are considered beneficial.
|
||||
*/
|
||||
@interface GSSpeechRecognitionEngine : NSObject
|
||||
|
||||
- (void) start;
|
||||
- (void) stop;
|
||||
|
||||
@end
|
||||
|
||||
@interface NSObject (GSSpeechRecognitionEngineDelegate)
|
||||
@end
|
||||
|
||||
@interface GSSpeechRecognitionEngine (Default)
|
||||
/**
|
||||
* Returns a new instance of the default speech engine.
|
||||
*/
|
||||
+ (GSSpeechRecognitionEngine*)defaultSpeechRecognitionEngine;
|
||||
@end
|
49
Tools/speech_recognizer/GSSpeechRecognitionEngine.m
Normal file
49
Tools/speech_recognizer/GSSpeechRecognitionEngine.m
Normal file
|
@ -0,0 +1,49 @@
|
|||
/* Implementation of class GSSpeechRecognitionEngine
|
||||
Copyright (C) 2019 Free Software Foundation, Inc.
|
||||
|
||||
By: Gregory John Casamento
|
||||
Date: Fri Dec 6 04:55:59 EST 2019
|
||||
|
||||
This file is part of the GNUstep Library.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110 USA.
|
||||
*/
|
||||
|
||||
#import "GSSpeechRecognitionEngine.h"
|
||||
|
||||
/**
|
||||
* Dummy implementation of a speech engine. Doesn't do anything.
|
||||
*/
|
||||
@implementation GSSpeechRecognitionEngine
|
||||
|
||||
+ (GSSpeechRecognitionEngine*) defaultSpeechEngine
|
||||
{
|
||||
return AUTORELEASE([[self alloc] init]);
|
||||
}
|
||||
|
||||
- (void) recognize
|
||||
{
|
||||
}
|
||||
|
||||
- (void) start
|
||||
{
|
||||
}
|
||||
|
||||
- (void) stop
|
||||
{
|
||||
}
|
||||
|
||||
@end
|
53
Tools/speech_recognizer/GSSpeechRecognitionServer.h
Normal file
53
Tools/speech_recognizer/GSSpeechRecognitionServer.h
Normal file
|
@ -0,0 +1,53 @@
|
|||
/* Interface of class GSSpeechRecognitionServer
|
||||
Copyright (C) 2019 Free Software Foundation, Inc.
|
||||
|
||||
By: Gregory John Casamento
|
||||
Date: Fri Dec 6 04:55:59 EST 2019
|
||||
|
||||
This file is part of the GNUstep Library.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110 USA.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <AppKit/NSSpeechRecognizer.h>
|
||||
|
||||
@class GSSpeechRecognitionEngine;
|
||||
|
||||
/**
|
||||
* GSSpeechRecognitionServer handles all of the engine-agnostic operations. Currently,
|
||||
* there aren't any, but when the on-screen text interface is added it should
|
||||
* go in here.
|
||||
*/
|
||||
@interface GSSpeechRecognitionServer : NSObject
|
||||
{
|
||||
GSSpeechRecognitionEngine *_engine;
|
||||
NSMutableArray *_blocking;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a shared instance of the speech server.
|
||||
*/
|
||||
+ (id)sharedServer;
|
||||
|
||||
// Add or remove from blocking list...
|
||||
- (void) addToBlockingRecognizers: (NSString *)s;
|
||||
- (void) removeFromBlockingRecognizers: (NSString *)s;
|
||||
- (BOOL) isBlocking: (NSString *)s;
|
||||
|
||||
// Connection...
|
||||
- (void) addClient;
|
||||
@end
|
146
Tools/speech_recognizer/GSSpeechRecognitionServer.m
Normal file
146
Tools/speech_recognizer/GSSpeechRecognitionServer.m
Normal file
|
@ -0,0 +1,146 @@
|
|||
/* Implementation of class GSSpeechRecognitionServer
|
||||
Copyright (C) 2019 Free Software Foundation, Inc.
|
||||
|
||||
By: Gregory John Casamento
|
||||
Date: Fri Dec 6 04:55:59 EST 2019
|
||||
|
||||
This file is part of the GNUstep Library.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110 USA.
|
||||
*/
|
||||
|
||||
#import "GSSpeechRecognitionServer.h"
|
||||
#import "GSSpeechRecognitionEngine.h"
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
static GSSpeechRecognitionServer *_sharedInstance;
|
||||
static int _clients = 0;
|
||||
|
||||
@implementation GSSpeechRecognitionServer
|
||||
|
||||
/**
|
||||
* Monitor connection...
|
||||
*/
|
||||
+ (void)connectionDied: (NSNotification*)aNotification
|
||||
{
|
||||
NSArray *objs = [[aNotification object] localObjects];
|
||||
NSEnumerator *en = [objs objectEnumerator];
|
||||
id o = nil;
|
||||
|
||||
if(_clients > 0)
|
||||
{
|
||||
_clients--;
|
||||
}
|
||||
|
||||
if(_clients == 0)
|
||||
{
|
||||
NSDebugLog(@"Client count is zero, exiting");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
NSDebugLog(@"NSSpeechRecognizer server connection count = %d after disconnection", _clients);
|
||||
while((o = [en nextObject]) != nil)
|
||||
{
|
||||
if ([o isKindOfClass: self])
|
||||
{
|
||||
RELEASE(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
_sharedInstance = [[self alloc] init];
|
||||
_clients = 0;
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserver: self
|
||||
selector: @selector(connectionDied:)
|
||||
name: NSConnectionDidDieNotification
|
||||
object: nil];
|
||||
}
|
||||
|
||||
+ (void)start
|
||||
{
|
||||
NSConnection *connection = [NSConnection defaultConnection];
|
||||
[connection setRootObject: _sharedInstance];
|
||||
RETAIN(connection);
|
||||
if (NO == [connection registerName: @"GSSpeechRecognitionServer"])
|
||||
{
|
||||
NSLog(@"Could not register name, make sure another server is not running.");
|
||||
return;
|
||||
}
|
||||
[[NSRunLoop currentRunLoop] run];
|
||||
}
|
||||
|
||||
+ (id)sharedServer
|
||||
{
|
||||
NSDebugLog(@"NSSpeechRecognizer server connection count = %d after connection", _clients);
|
||||
return _sharedInstance;
|
||||
}
|
||||
|
||||
- (void) addClient
|
||||
{
|
||||
_clients++;
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if (nil == (self = [super init]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
_engine = [GSSpeechRecognitionEngine defaultSpeechRecognitionEngine];
|
||||
if (nil == _engine)
|
||||
{
|
||||
[self release];
|
||||
return nil;
|
||||
}
|
||||
else
|
||||
{
|
||||
NSDebugLog(@"Got engine starting... %@", _engine);
|
||||
[_engine start];
|
||||
}
|
||||
|
||||
_blocking = [[NSMutableArray alloc] initWithCapacity: 10];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[_engine stop];
|
||||
RELEASE(_engine);
|
||||
RELEASE(_blocking);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void) addToBlockingRecognizers: (NSString *)s
|
||||
{
|
||||
[_blocking addObject: s];
|
||||
}
|
||||
|
||||
- (void) removeFromBlockingRecognizers: (NSString *)s
|
||||
{
|
||||
[_blocking removeObject: s];
|
||||
}
|
||||
|
||||
- (BOOL) isBlocking: (NSString *)s
|
||||
{
|
||||
return [[_blocking lastObject] isEqualToString: s];
|
||||
}
|
||||
|
||||
@end
|
233
Tools/speech_recognizer/PocketsphinxSpeechRecognitionEngine.m
Normal file
233
Tools/speech_recognizer/PocketsphinxSpeechRecognitionEngine.m
Normal file
|
@ -0,0 +1,233 @@
|
|||
/* Implementation of class PocketsphinxSpeechRecognitionEngine
|
||||
Copyright (C) 2019 Free Software Foundation, Inc.
|
||||
|
||||
By: Gregory John Casamento
|
||||
Date: Fri Dec 6 04:55:59 EST 2019
|
||||
|
||||
This file is part of the GNUstep Library.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110 USA.
|
||||
*/
|
||||
|
||||
#import "GSSpeechRecognitionEngine.h"
|
||||
#import <Foundation/NSDistributedNotificationCenter.h>
|
||||
|
||||
#include <sphinxbase/err.h>
|
||||
#include <sphinxbase/ad.h>
|
||||
#include <pocketsphinx/pocketsphinx.h>
|
||||
|
||||
/**
|
||||
* Implementation of a speech engine using pocketsphinx. This should be the default
|
||||
* for resource-constrained platforms.
|
||||
*/
|
||||
|
||||
#define MODELDIR "/share/pocketsphinx/model"
|
||||
|
||||
static const arg_t cont_args_def[] = {
|
||||
POCKETSPHINX_OPTIONS,
|
||||
/* Argument file. */
|
||||
{"-argfile",
|
||||
ARG_STRING,
|
||||
NULL,
|
||||
"Argument file giving extra arguments."},
|
||||
{"-adcdev",
|
||||
ARG_STRING,
|
||||
NULL,
|
||||
"Name of audio device to use for input."},
|
||||
{"-infile",
|
||||
ARG_STRING,
|
||||
NULL,
|
||||
"Audio file to transcribe."},
|
||||
{"-inmic",
|
||||
ARG_BOOLEAN,
|
||||
"yes",
|
||||
"Transcribe audio from microphone."},
|
||||
{"-time",
|
||||
ARG_BOOLEAN,
|
||||
"no",
|
||||
"Print word times in file transcription."},
|
||||
CMDLN_EMPTY_OPTION
|
||||
};
|
||||
|
||||
@interface PocketsphinxSpeechRecognitionEngine : GSSpeechRecognitionEngine
|
||||
{
|
||||
ps_decoder_t *ps;
|
||||
cmd_ln_t *config;
|
||||
FILE *fh;
|
||||
char const *uttid;
|
||||
int16 buf[512];
|
||||
int rv;
|
||||
int32 score;
|
||||
NSThread *_listeningThread;
|
||||
id<NSSpeechRecognizerDelegate> _delegate;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation PocketsphinxSpeechRecognitionEngine
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if ((self = [super init]) != nil)
|
||||
{
|
||||
char *arg[3];
|
||||
arg[0] = "";
|
||||
arg[1] = "-inmic";
|
||||
arg[2] = "yes";
|
||||
|
||||
config = cmd_ln_parse_r(NULL, cont_args_def, 3, arg, TRUE);
|
||||
// turn off pocketsphinx output
|
||||
err_set_logfp(NULL);
|
||||
err_set_debug_level(0);
|
||||
ps_default_search_args(config);
|
||||
ps = ps_init(config);
|
||||
if (ps == NULL)
|
||||
{
|
||||
cmd_ln_free_r(config);
|
||||
NSLog(@"Could not start server");
|
||||
return nil;
|
||||
}
|
||||
_listeningThread = nil;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) _recognizedWord: (NSString *)word
|
||||
{
|
||||
[[NSDistributedNotificationCenter defaultCenter]
|
||||
postNotificationName: GSSpeechRecognizerDidRecognizeWordNotification
|
||||
object: word
|
||||
userInfo: nil];
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: This code is derived from continuous.c under pocketsphinx
|
||||
* which is MIT licensed
|
||||
* Main utterance processing loop:
|
||||
* while (YES) {
|
||||
* start utterance and wait for speech to process
|
||||
* decoding till end-of-utterance silence will be detected
|
||||
* print utterance result;
|
||||
* }
|
||||
*/
|
||||
- (void) recognize
|
||||
{
|
||||
ad_rec_t *ad;
|
||||
int16 adbuf[2048];
|
||||
BOOL utt_started, in_speech;
|
||||
int32 k;
|
||||
char const *hyp;
|
||||
|
||||
NSDebugLog(@"** Starting speech recognition loop");
|
||||
if ((ad = ad_open_dev(cmd_ln_str_r(config, "-adcdev"),
|
||||
(int) cmd_ln_float32_r(config,
|
||||
"-samprate"))) == NULL)
|
||||
{
|
||||
NSLog(@"Failed to open audio device");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ad_start_rec(ad) < 0)
|
||||
{
|
||||
NSLog(@"Failed to start recording");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ps_start_utt(ps) < 0)
|
||||
{
|
||||
NSLog(@"Failed to start utterance");
|
||||
return;
|
||||
}
|
||||
|
||||
utt_started = NO;
|
||||
NSDebugLog(@"Ready.... <%@, %d>", _listeningThread, [_listeningThread isCancelled]);
|
||||
|
||||
while([_listeningThread isCancelled] == NO && _listeningThread != nil)
|
||||
{
|
||||
if ((k = ad_read(ad, adbuf, 2048)) < 0)
|
||||
{
|
||||
NSLog(@"Failed to read audio");
|
||||
break;
|
||||
}
|
||||
|
||||
ps_process_raw(ps, adbuf, k, FALSE, FALSE);
|
||||
in_speech = ps_get_in_speech(ps);
|
||||
|
||||
if (in_speech && !utt_started)
|
||||
{
|
||||
utt_started = YES;
|
||||
NSDebugLog(@"Listening...");
|
||||
}
|
||||
|
||||
if (!in_speech && utt_started)
|
||||
{
|
||||
/* speech -> silence transition, time to start new utterance */
|
||||
ps_end_utt(ps);
|
||||
hyp = ps_get_hyp(ps, NULL);
|
||||
if (hyp != NULL)
|
||||
{
|
||||
NSString *recognizedString = [NSString stringWithCString: hyp
|
||||
encoding: NSUTF8StringEncoding];
|
||||
[self performSelectorOnMainThread: @selector(_recognizedWord:)
|
||||
withObject: recognizedString
|
||||
waitUntilDone: NO];
|
||||
NSDebugLog(@"Word: %s", hyp);
|
||||
}
|
||||
|
||||
if (ps_start_utt(ps) < 0)
|
||||
{
|
||||
NSLog(@"Failed to start utterance");
|
||||
}
|
||||
|
||||
utt_started = NO;
|
||||
NSDebugLog(@"Ready.... <%@, %d>", _listeningThread, [_listeningThread isCancelled]);
|
||||
}
|
||||
[NSThread sleepForTimeInterval: 0.01];
|
||||
}
|
||||
|
||||
// Close everything...
|
||||
ps_end_utt(ps);
|
||||
ad_close(ad);
|
||||
}
|
||||
|
||||
- (void) start
|
||||
{
|
||||
_listeningThread =
|
||||
[[NSThread alloc] initWithTarget: self
|
||||
selector: @selector(recognize)
|
||||
object: nil];
|
||||
[_listeningThread setName: @"Speech Recognition Loop"];
|
||||
NSLog(@"Starting - Thread info for speech recognition server %@", _listeningThread);
|
||||
[_listeningThread start];
|
||||
}
|
||||
|
||||
- (void) stop
|
||||
{
|
||||
NSLog(@"Stop listening thread %@", _listeningThread);
|
||||
[_listeningThread cancel];
|
||||
RELEASE(_listeningThread);
|
||||
_listeningThread = nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation GSSpeechRecognitionEngine (Pocketsphinx)
|
||||
|
||||
+ (GSSpeechRecognitionEngine*)defaultSpeechRecognitionEngine
|
||||
{
|
||||
return AUTORELEASE([[PocketsphinxSpeechRecognitionEngine alloc] init]);
|
||||
}
|
||||
|
||||
@end
|
12
Tools/speech_recognizer/main.m
Normal file
12
Tools/speech_recognizer/main.m
Normal file
|
@ -0,0 +1,12 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface GSSpeechRecognitionServer
|
||||
+ (void)start;
|
||||
@end
|
||||
|
||||
int main(void)
|
||||
{
|
||||
[NSAutoreleasePool new];
|
||||
[GSSpeechRecognitionServer start];
|
||||
return 0;
|
||||
}
|
|
@ -8,7 +8,11 @@ ADDITIONAL_DEPENDS = @LIBS@
|
|||
|
||||
# Build speech and sound.
|
||||
BUILD_SPEECH=@BUILD_SPEECH@
|
||||
BUILD_SPEECH_RECOGNIZER=@BUILD_SPEECH_RECOGNIZER@
|
||||
BUILD_SOUND=@BUILD_SOUND@
|
||||
RECOGNIZER_BASE_LIBS=@RECOGNIZER_BASE_LIBS@
|
||||
RECOGNIZER_BASE_CFLAGS=@RECOGNIZER_BASE_CFLAGS@
|
||||
RECOGNIZER_ENGINE_CLASS=@RECOGNIZER_ENGINE_CLASS@
|
||||
|
||||
# CUPS
|
||||
GSCUPS_CFLAGS = @GSCUPS_CFLAGS@
|
||||
|
|
86
configure
vendored
86
configure
vendored
|
@ -635,6 +635,10 @@ GSCUPS_LIBS
|
|||
GSCUPS_LDFLAGS
|
||||
GSCUPS_CFLAGS
|
||||
have_cups
|
||||
RECOGNIZER_ENGINE_CLASS
|
||||
RECOGNIZER_BASE_CFLAGS
|
||||
RECOGNIZER_BASE_LIBS
|
||||
BUILD_SPEECH_RECOGNIZER
|
||||
BUILD_SPEECH
|
||||
BUILD_SOUND
|
||||
HAVE_ICU
|
||||
|
@ -729,6 +733,7 @@ with_icu_library
|
|||
enable_aspell
|
||||
enable_sound
|
||||
enable_speech
|
||||
enable_speech_recognizer
|
||||
enable_cups
|
||||
'
|
||||
ac_precious_vars='build_alias
|
||||
|
@ -1384,6 +1389,7 @@ Optional Features:
|
|||
--disable-aspell Disable aspell for spellchecker
|
||||
--disable-sound Disable sound
|
||||
--disable-speech Disable speech server
|
||||
--disable-speech-recognizer Disable speech recognition server
|
||||
--disable-cups Disable cups printing support
|
||||
|
||||
Optional Packages:
|
||||
|
@ -5662,6 +5668,86 @@ fi
|
|||
fi
|
||||
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# NSSpeechRecognizer
|
||||
#--------------------------------------------------------------------
|
||||
# Check whether --enable-speech-recognizer was given.
|
||||
if test "${enable_speech_recognizer+set}" = set; then :
|
||||
enableval=$enable_speech_recognizer;
|
||||
else
|
||||
enable_speech_recognizer=yes
|
||||
fi
|
||||
|
||||
BUILD_SPEECH_RECOGNIZER=
|
||||
|
||||
# has pocketsphinx, for speech recognition.
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ps_start_utt in -lpocketsphinx" >&5
|
||||
$as_echo_n "checking for ps_start_utt in -lpocketsphinx... " >&6; }
|
||||
if ${ac_cv_lib_pocketsphinx_ps_start_utt+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
ac_check_lib_save_LIBS=$LIBS
|
||||
LIBS="-lpocketsphinx $LIBS"
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
/* Override any GCC internal prototype to avoid an error.
|
||||
Use char because int might match the return type of a GCC
|
||||
builtin and then its argument prototype would still apply. */
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
char ps_start_utt ();
|
||||
int
|
||||
main ()
|
||||
{
|
||||
return ps_start_utt ();
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_link "$LINENO"; then :
|
||||
ac_cv_lib_pocketsphinx_ps_start_utt=yes
|
||||
else
|
||||
ac_cv_lib_pocketsphinx_ps_start_utt=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext \
|
||||
conftest$ac_exeext conftest.$ac_ext
|
||||
LIBS=$ac_check_lib_save_LIBS
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pocketsphinx_ps_start_utt" >&5
|
||||
$as_echo "$ac_cv_lib_pocketsphinx_ps_start_utt" >&6; }
|
||||
if test "x$ac_cv_lib_pocketsphinx_ps_start_utt" = xyes; then :
|
||||
have_speech_recognizer=yes
|
||||
else
|
||||
have_speech_recognizer=no
|
||||
fi
|
||||
|
||||
for ac_header in pocketsphinx/pocketsphinx_export.h
|
||||
do :
|
||||
ac_fn_c_check_header_mongrel "$LINENO" "pocketsphinx/pocketsphinx_export.h" "ac_cv_header_pocketsphinx_pocketsphinx_export_h" "$ac_includes_default"
|
||||
if test "x$ac_cv_header_pocketsphinx_pocketsphinx_export_h" = xyes; then :
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define HAVE_POCKETSPHINX_POCKETSPHINX_EXPORT_H 1
|
||||
_ACEOF
|
||||
have_pocketsphinx=yes
|
||||
else
|
||||
have_pocketsphinx=no
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
if test $have_pocketsphinx = yes -a $have_speech_recognizer = yes -a $enable_speech_recognizer = yes; then
|
||||
BUILD_SPEECH_RECOGNIZER="speech_recognizer"
|
||||
RECOGNIZER_BASE_LIBS=`pkg-config --libs pocketsphinx sphinxbase`
|
||||
RECOGNIZER_BASE_CFLAGS=`pkg-config --cflags pocketsphinx sphinxbase`
|
||||
RECOGNIZER_ENGINE_CLASS=PocketsphinxSpeechRecognitionEngine.m
|
||||
fi
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# Find CUPS
|
||||
#--------------------------------------------------------------------
|
||||
|
|
22
configure.ac
22
configure.ac
|
@ -538,6 +538,28 @@ if test $have_flite = yes -a $have_speech = yes -a $enable_speech = yes; then
|
|||
fi
|
||||
AC_SUBST(BUILD_SPEECH)
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# NSSpeechRecognizer
|
||||
#--------------------------------------------------------------------
|
||||
AC_ARG_ENABLE(speech-recognizer,
|
||||
[ --disable-speech-recognizer Disable speech recognition server],,
|
||||
enable_speech_recognizer=yes)
|
||||
BUILD_SPEECH_RECOGNIZER=
|
||||
|
||||
# has pocketsphinx, for speech recognition.
|
||||
AC_CHECK_LIB(pocketsphinx, ps_start_utt, have_speech_recognizer=yes, have_speech_recognizer=no)
|
||||
AC_CHECK_HEADERS(pocketsphinx/pocketsphinx_export.h, have_pocketsphinx=yes, have_pocketsphinx=no)
|
||||
if test $have_pocketsphinx = yes -a $have_speech_recognizer = yes -a $enable_speech_recognizer = yes; then
|
||||
BUILD_SPEECH_RECOGNIZER="speech_recognizer"
|
||||
RECOGNIZER_BASE_LIBS=`pkg-config --libs pocketsphinx sphinxbase`
|
||||
RECOGNIZER_BASE_CFLAGS=`pkg-config --cflags pocketsphinx sphinxbase`
|
||||
RECOGNIZER_ENGINE_CLASS=PocketsphinxSpeechRecognitionEngine.m
|
||||
fi
|
||||
AC_SUBST(BUILD_SPEECH_RECOGNIZER)
|
||||
AC_SUBST(RECOGNIZER_BASE_LIBS)
|
||||
AC_SUBST(RECOGNIZER_BASE_CFLAGS)
|
||||
AC_SUBST(RECOGNIZER_ENGINE_CLASS)
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# Find CUPS
|
||||
#--------------------------------------------------------------------
|
||||
|
|
|
@ -11,10 +11,12 @@ install_gnustep_make() {
|
|||
cd tools-make
|
||||
if [ -n "$RUNTIME_VERSION" ]
|
||||
then
|
||||
echo "RUNTIME_VERSION=$RUNTIME_VERSION" > GNUstep.conf
|
||||
WITH_RUNTIME_ABI="--with-runtime-abi=${RUNTIME_VERSION}"
|
||||
else
|
||||
WITH_RUNTIME_ABI=""
|
||||
fi
|
||||
./configure --prefix=$DEP_ROOT --with-library-combo=$LIBRARY_COMBO --with-user-config-file=$PWD/GNUstep.conf
|
||||
make install
|
||||
./configure --prefix=$DEP_ROOT --with-library-combo=$LIBRARY_COMBO $WITH_RUNTIME_ABI
|
||||
make install
|
||||
echo Objective-C build flags: `$HOME/staging/bin/gnustep-config --objc-flags`
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue