+/* ==========================================================================
+
+ Visible bell and beep.
+
+ ========================================================================== */
+
+
+@interface EmacsBell : NSImageView
+{
+ // Number of currently active bell:s.
+ unsigned int nestCount;
+ bool isAttached;
+}
+- (void)show:(NSView *)view;
+- (void)hide;
+- (void)remove;
+@end
+
+@implementation EmacsBell
+
+- (id)init;
+{
+ NSTRACE ("[EmacsBell init]");
+ if ((self = [super init]))
+ {
+ nestCount = 0;
+ isAttached = false;
+#ifdef NS_IMPL_GNUSTEP
+ // GNUstep doesn't provide named images. This was reported in
+ // 2011, see https://savannah.gnu.org/bugs/?33396
+ //
+ // As a drop in replacement, a semitransparent gray square is used.
+ self.image = [[NSImage alloc] initWithSize:NSMakeSize(32, 32)];
+ [self.image lockFocus];
+ [[NSColor colorForEmacsRed:0.5 green:0.5 blue:0.5 alpha:0.5] set];
+ NSRectFill(NSMakeRect(0, 0, 32, 32));
+ [self.image unlockFocus];
+#else
+ self.image = [NSImage imageNamed:NSImageNameCaution];
+#endif
+ }
+ return self;
+}
+
+- (void)show:(NSView *)view
+{
+ NSTRACE ("[EmacsBell show:]");
+ NSTRACE_MSG ("nestCount: %u", nestCount);
+
+ // Show the image, unless it's already shown.
+ if (nestCount == 0)
+ {
+ NSRect rect = [view bounds];
+ NSPoint pos;
+ pos.x = rect.origin.x + (rect.size.width - self.image.size.width )/2;
+ pos.y = rect.origin.y + (rect.size.height - self.image.size.height)/2;
+
+ [self setFrameOrigin:pos];
+ [self setFrameSize:self.image.size];
+
+ isAttached = true;
+ [[[view window] contentView] addSubview:self
+ positioned:NSWindowAbove
+ relativeTo:nil];
+ }
+
+ ++nestCount;
+
+ [self performSelector:@selector(hide) withObject:self afterDelay:0.5];
+}
+
+
+- (void)hide
+{
+ // Note: Trace output from this method isn't shown, reason unknown.
+ // NSTRACE ("[EmacsBell hide]");
+
+ if (nestCount > 0)
+ --nestCount;
+
+ // Remove the image once the last bell became inactive.
+ if (nestCount == 0)
+ {
+ [self remove];
+ }
+}
+
+
+-(void)remove
+{
+ if (isAttached)
+ {
+ [self removeFromSuperview];
+ isAttached = false;
+ }
+}
+
+@end
+
+
+static EmacsBell * bell_view = nil;
+