Home | History | Annotate | Download | only in macos
      1 /*
      2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
      3  *
      4  * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
      5  *
      6  * The contents of this file are subject to the terms of either the GNU Lesser
      7  * General Public License Version 2.1 only ("LGPL") or the Common Development and
      8  * Distribution License ("CDDL")(collectively, the "License"). You may not use this
      9  * file except in compliance with the License. You can obtain a copy of the CDDL at
     10  * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
     11  * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
     12  * specific language governing permissions and limitations under the License. When
     13  * distributing the software, include this License Header Notice in each file and
     14  * include the full text of the License in the License file as well as the
     15  * following notice:
     16  *
     17  * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
     18  * (CDDL)
     19  * For Covered Software in this distribution, this License shall be governed by the
     20  * laws of the State of California (excluding conflict-of-law provisions).
     21  * Any litigation relating to this License shall be subject to the jurisdiction of
     22  * the Federal Courts of the Northern District of California and the state courts
     23  * of the State of California, with venue lying in Santa Clara County, California.
     24  *
     25  * Contributor(s):
     26  *
     27  * If you wish your version of this file to be governed by only the CDDL or only
     28  * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
     29  * include this software in this distribution under the [CDDL or LGPL Version 2.1]
     30  * license." If you don't indicate a single choice of license, a recipient has the
     31  * option to distribute your version of this file under either the CDDL or the LGPL
     32  * Version 2.1, or to extend the choice of license to its licensees as provided
     33  * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
     34  * Version 2 license, then the option applies only if the new code is made subject
     35  * to such option by the copyright holder.
     36  */
     37 
     38 #import "Carbon/Carbon.h"
     39 #import "CandidateWindow.h"
     40 
     41 static void tuningFrameForScreen (NSRect *, NSSize, NSRect);
     42 
     43 @interface CandidateView : NSView {
     44     NSAttributedString  *_string;
     45 }
     46 
     47 -(void) setAttributedString:(NSAttributedString *)str;
     48 
     49 @end
     50 
     51 @implementation CandidateView
     52 
     53 -(void) setAttributedString:(NSAttributedString *)str
     54 {
     55     [str retain];
     56     [_string release];
     57     _string = str;
     58     [self setNeedsDisplay:YES];
     59 }
     60 
     61 - (void)drawRect:(NSRect)rect
     62 {
     63     if (!_string)
     64         return;
     65 
     66     NSPoint stringOrigin;
     67     NSSize stringSize = [_string size];
     68     stringOrigin.x = rect.origin.x + ( rect.size.width - stringSize.width)/2;
     69     stringOrigin.y = rect.origin.y + ( rect.size.height - stringSize.height)/2;
     70     [_string drawAtPoint:stringOrigin];
     71 }
     72 
     73 - (void) dealloc
     74 {
     75     [_string release];
     76     [super dealloc];
     77 }
     78 
     79 @end
     80 
     81 @implementation CandidateWindow
     82 
     83 -(id)init
     84 {
     85     _font = [[NSFont fontWithName:@"Hei" size:16] retain];
     86     _bgColor =  [[NSColor colorWithDeviceRed:1.0 green:0.5 blue:0.0 alpha:0.8] retain];
     87     _fgColor = [[NSColor whiteColor] retain];
     88     _hlColor = [[NSColor blueColor] retain];
     89 
     90     _attr = [[NSMutableDictionary alloc] init];
     91     [_attr setObject:_fgColor forKey:NSForegroundColorAttributeName];
     92     [_attr setObject:_font forKey:NSFontAttributeName];
     93 
     94     _window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0,0,0,0)
     95                                 styleMask:NSBorderlessWindowMask
     96                                 backing:NSBackingStoreBuffered
     97                                 defer:NO];
     98 
     99     [_window setLevel:NSScreenSaverWindowLevel];
    100     [_window setHasShadow: YES];
    101     [_window setOpaque:NO];
    102 
    103     [_window setBackgroundColor:_bgColor];
    104 
    105     _view = [[CandidateView alloc] initWithFrame:[[_window contentView] frame]];
    106     [_window setContentView:_view];
    107 
    108     return self;
    109 }
    110 
    111 -(NSFont *)font
    112 {
    113     return _font;
    114 }
    115 
    116 -(void)setFont:(NSFont*)font
    117 {
    118     [font retain];
    119     [_font release];
    120     _font = font;
    121     [_attr setObject:_font forKey:NSFontAttributeName];
    122 }
    123 
    124 -(NSColor *)bgColor
    125 {
    126     return _bgColor;
    127 }
    128 
    129 -(void)setBgColor:(NSColor*)color
    130 {
    131     [color retain];
    132     [_bgColor release];
    133     _bgColor = color;
    134     [_window setBackgroundColor:color];
    135 }
    136 
    137 -(NSColor *)fgColor
    138 {
    139     return _fgColor;
    140 }
    141 
    142 -(void)setFgColor:(NSColor*)color
    143 {
    144     [color retain];
    145     [_fgColor release];
    146     _fgColor = color;
    147 }
    148 
    149 -(NSColor *)hlColor
    150 {
    151     return _hlColor;
    152 }
    153 
    154 -(void)setHlColor:(NSColor*)color
    155 {
    156     [color retain];
    157     [_hlColor release];
    158     _hlColor = color;
    159 }
    160 
    161 -(void)showCandidates:(NSArray *)candiArray around:(NSRect)cursorRect
    162 {
    163     if ([candiArray count] == 0) {
    164         [self hideCandidates];
    165         return;
    166     }
    167 
    168     [_attr setObject:_fgColor forKey:NSForegroundColorAttributeName];
    169     [_attr setObject:_font forKey:NSFontAttributeName];
    170 
    171     int i;
    172     NSMutableAttributedString *string = [[NSMutableAttributedString alloc] init];
    173     for (i=0; i<[candiArray count]; i++) {
    174         NSString *str = [NSString stringWithFormat:@"%d.%@ ", i+1, [candiArray objectAtIndex:i]];
    175         NSAttributedString *astr = [[[NSAttributedString alloc] initWithString:str attributes:_attr] autorelease];
    176         [string appendAttributedString:astr];
    177 
    178         if (i==0)
    179             [string addAttribute:NSForegroundColorAttributeName
    180                     value:_hlColor
    181                     range:NSMakeRange(0, [str length])];
    182     }
    183 
    184     NSRect winRect = [_window frame];
    185     NSSize strSize = [string size];
    186 
    187     tuningFrameForScreen (&winRect, strSize, cursorRect);
    188     [_window setFrame:winRect display:NO];
    189 
    190     [(CandidateView*)_view setAttributedString:string];
    191     [string release];
    192 
    193     [_window orderFront:nil];
    194 }
    195 
    196 -(void)hideCandidates
    197 {
    198     [_window orderOut:self];
    199 }
    200 
    201 - (void) dealloc
    202 {
    203     [_font release];
    204     [_bgColor release];
    205     [_fgColor release];
    206     [_hlColor release];
    207     [_attr release];
    208     [_view release];
    209     [_window release];
    210     [super dealloc];
    211 }
    212 
    213 @end
    214 
    215 static void tuningFrameForScreen (NSRect *winRect, NSSize strSize, NSRect cursorRect)
    216 {
    217     /* caculate the initial window's size */
    218     winRect->size.height = strSize.height+5;
    219     winRect->size.width = strSize.width+5;
    220     winRect->origin.x = cursorRect.origin.x + 2;
    221     winRect->origin.y = cursorRect.origin.y - winRect->size.height -2;
    222 
    223     /* find a proper screen by input cursor */
    224     NSRect screenRect = [[NSScreen mainScreen] frame];
    225     NSArray *screens =[NSScreen screens];
    226     int i, num_of_scrs = [screens count];
    227 
    228     /* no choices, just use mainScreen */
    229     if (num_of_scrs == 1)
    230         goto FOUND_SCREEN;
    231 
    232     for (i=0; i<num_of_scrs; i++) {
    233         NSScreen *screen = [screens objectAtIndex:i];
    234         NSRect rect = [screen frame];
    235         if (NSPointInRect (cursorRect.origin, rect)) {
    236             screenRect = rect;
    237             goto FOUND_SCREEN;
    238         }
    239     }
    240 
    241     /* find a proper screen by mouse position */
    242     HIPoint p;
    243     HIGetMousePosition (kHICoordSpaceScreenPixel, NULL, &p);
    244     NSPoint mousePosition;
    245     mousePosition.x = p.x;
    246     mousePosition.y = screenRect.size.height - p.y;
    247 
    248     for (i=0; i<num_of_scrs; i++) {
    249         NSScreen *screen = [screens objectAtIndex:i];
    250         NSRect rect = [screen frame];
    251         if (NSPointInRect (mousePosition, rect)) {
    252             screenRect = rect;
    253             goto FOUND_SCREEN;
    254         }
    255     }
    256 
    257 FOUND_SCREEN:;
    258     CGFloat min_x = NSMinX (screenRect), max_x = NSMaxX (screenRect);
    259     CGFloat min_y = NSMinY (screenRect);
    260 
    261     if (winRect->origin.x > max_x - winRect->size.width)
    262         winRect->origin.x = max_x - winRect->size.width;
    263 
    264     if (winRect->origin.x < min_x)
    265         winRect->origin.x = min_x;
    266 
    267     if (winRect->origin.y < min_y)
    268         winRect->origin.y = cursorRect.origin.y > min_y?
    269                             cursorRect.origin.y + cursorRect.size.height + 2:
    270                             min_y;
    271 }
    272