Showing posts with label objective-c. Show all posts
Showing posts with label objective-c. Show all posts

Thursday, October 3, 2019

Generating "Always On Top" NSWindow in macOS across all detected displays

Also: Using UIKit & Cocoa Frameworks using Objective-C

In macOS or OS X, written in either Objective-C or Swift Langues, you may want an application to run both in full screen and at the top most level in the window layers, covering all apps behind it. This is known in some circles as the Z-Order or z dimension in a x-y-z Cartesian Plane. It's aptly named after Frenchman Rene Descartes, a highly revered & gifted Mathematician, and also Philosopher who made invaluable contributions to his respective fields. The x, y is the horizontal axis and vertical axis, while z-axis is the depth when you visualise the screen in three dimensions (3-D).

This snippet below I had written in Obj-C, and can be ported to Swift easily. The function is quite rudimentary in syntax and structuring. In a nutshell it enumerates all of the displays, and places a semi-transparent window, running full screen with a floating point opacity alpha value. If you want the background apps to still be visible then it's imperative that you set a low alpha float value (<= 0.5f).

Also, there are plenty of customisations possible to configure with classes NSScreen, NSWindow, and more. You can add a fullscreen subview from an NSImage or NSImageView and affix it to the primary screen, or all screens, whichever you fancy. There are also passed arguments specifying various colour values using class NSColor (can be specified in either hexadecimal #fffff or RGB float values eg: {1f,1f,1f}). You can also customise the behaviour of the full screen window, whether it can be resized or borderless, it's completely up to you! There are a plethora of possible configurations and styles defined in the class specifications or header.

This first function is a helper function that returns a UIImageView object based on input of image and frame, which are arguments passed into method. It sets the boundaries and affixes the NSImage as an NSImageView, as well as the x,y,h,w as a CGRect dimension frame.



+ (NSImageView *) getImage:(NSString *) image
                     frame:(CGRect) frame
{
    NSImageView *imageView = [[NSImageView alloc] init];
    [imageView setFrame:frame];
    [imageView setImage:[NSImage imageNamed:image]];
    [imageView setBoundsOrigin: NSZeroPoint];
    return imageView;
}


Below this function modifies the enumerated Window whilst passing in the frame (x,y, w, h dimensions), and the Screen which are passed in. It also specifies the window behaviour and background colour, which in this case it's an NSColor defined as a constant:



+ (NSWindow *) modifyWindow:(NSWindow *) window
                      frame:(NSRect) frame
                     screen:(NSScreen *) screen
{

    [window setBackgroundColor:t_colour];
    [window setCollectionBehavior:  
  NSWindowCollectionBehaviorStationary |
                                    NSWindowCollectionBehaviorCanJoinAllSpaces |
                                    NSWindowCollectionBehaviorFullScreenAuxiliary |
                                    NSWindowCollectionBehaviorTransient ];
    [window makeKeyAndOrderFront:NSApp];
    [window setAlphaValue:kConstAlphaDefault];
    [window setLevel:kCGMainMenuWindowLevel-1];
    [window toggleFullScreen:nil];
    return window;
}


When the NSScreens are enumerated, each member is sent as an argument screen, also idx number (which is redundant since we can simply get the screen index internally from the members of the class). Anyhow, we create an NSRect for the dimensions (x,y, height and width). Since we are interested in covering the entire space of said screen we use the size height and width, and start at 0, 0 (x,y). We finally affix an NSImageView with kConstImageBlock with is just a char constant defined in some header. This subview function was the first function we described in the first code snippet. Also there is a flag to detect the "primary" display. The NSImageView is only affixed as a subview on the "primary" display. The other displays just get a coloured in, however if you desire you can add the Image by removing the if then conditional, see below:



+ (void) displayBlockScreen:(NSScreen *) screen
                      index:(int) idx
{
    NSMutableArray* windows = [[NSMutableArray alloc] init];
    NSRect frame = NSMakeRect(0,
                              0,
                              [screen frame].size.width,
                              [screen frame].size.height);
    NSWindow *window  = [[NSWindow alloc] initWithContentRect
frame styleMask: NSWindowStyleMaskBorderless backing: NSBackingStoreBuffered defer: NO screen: screen];
    
    if (screen == [NSScreen mainScreen])
    {
        NSImageView *imageView = [self getImage:kConstImageBlock frame:frame];
        [window.contentView addSubview:imageView];
    }
    [windows addObject:[self modifyWindow:window
                                    frame:frame
                                   screen:screen]];
}


Last but certainly not least is the very first, entry point function which does exactly what it's name indicates, displayEnum. It sequentially enumerates thru all of the detected NSScreen screens value array, starting at index 0, and accounting for each of the Monitor Screen Displays that are found. The "do while" loop can be a "for next" loop or a bunch of other iterator types, but "do while" was on my mind, and was feeling adventurous. The loop stops incrementing the index as the array count is finally reached and the condition is met, see below:


+ (voiddisplayEnum
{
    int idx = 0;
    NSArray *screens = [NSScreen screens];
    NSUInteger count = [screens count];
    
    NSLog(@"\n\tTotal Screens: [%lu]\n\n", count);
    
    do {
        NSScreen *screen = [screens objectAtIndex:idx];
        [self displayBlockScreen:screen
                           index:idx];
        idx++;
    while (idx < count);
}


Obliged you chose to read thru this, and visiting my ghetto coding blog.I sincerely hope that this code can be of some service to you, a software engineer trying to dynamically generate full covering, always on top screen(s), with additional need for image subviews affixing to the respective detected window(s). Hopefully the code above can easily facilitate the need to detect multiple display configurations, as well as a designation of a "primary" display. Surely out there somewhere in the deepest recesses of this fine universe exists a use case scenario, imperatively requesting such specialised screen and window behaviour described above? I'm quite confident that the practical application exists somewhere in the vast macOS user world obusiness, corporate, healtheducation, maybe even cyber-security. 

Cheers & until next time,

-Apollo

Tuesday, January 19, 2016

Change Resolution pixels of iOS Game using Unity3D 5.3.1f1 in Xcode 7.x

To change the resolution in Unity 5.3.1f1 is difficult in iOS when it comes to granularity of the device. Prior to 5.3.x, you could simply put in different modes for resolution. Auto Performance, Native Resolution, and Auto Quality were some of the few.  With the new version you can not adjust this so it requires that your hands get a bit dirty.

See below in DisplayManager.mm. look for UnityScreenScaleFactor:

Modify as below:

extern "C" float UnityScreenScaleFactor(UIScreen* screen)
{
// we should query nativeScale if available to get the true device resolution
// this way we avoid unnecessarily large frame buffers and downscaling.
// e.g. iPhone 6+ pretends to be a x3 device, while its physical screen is x2.6 something.
    
    /* Amit's custom code screen size */
    float resMult = 0.75f;
    switch(UnityDeviceGeneration())
    {
        case deviceiPadPro1Gen:     resMult = 0.6f;     break;
        case deviceiPhoneUnknown:   resMult = 0.75f;    break;
        case deviceiPhone6:         resMult = 0.75f; break;
        case deviceiPhone7:         resMult = 0.75f; break;
        case deviceiPhone6Plus:     resMult = 0.6f;     break;
        case deviceiPhone6S:        resMult = 0.75f; break;
        case deviceiPhone6SPlus:    resMult = 0.6f;     break;
        case deviceiPhone4:         resMult = 0.6f; break;
        case deviceiPad3Gen:        resMult = 0.5f; break;
        case deviceiPad4Gen:        resMult = 0.5f; break;
        case deviceiPadAir1:        resMult = 0.5f; break;
        case deviceiPadAir2:        resMult = 0.5f; break;
        case deviceiPadMini2Gen:    resMult = 0.5f; break;
        case deviceiPadMini3Gen:    resMult = 0.5f; break;
        case deviceiPadUnknown:     resMult = 0.5f;     break;
        default:                    resMult = 0.8f;     break;
    }

    if([screen respondsToSelector:@selector(nativeScale)])
{
// On AppleTV screen.nativeScale returns NaN when device is in sleep mode
if (isnan(screen.nativeScale))
return 1.0f;
else
return screen.nativeScale * resMult;
}
return screen.scale * resMult;

}


As you can see above, the resMult is what you multiply the resolution accordingly. For example if you take a 0.5f multiplyer on an iPad Retina (2048x1536) it'll turn your resolution to 1/2 or 0.5 of it which is essentially 1024x768.

Why you may ask would you want to do this? Speed, simply. Some games run entirely to slow in full resolution with Unity3D. It is optimal to use a multiplyer and scale down for older devices with AA or AAA games graphics.

Sunday, December 22, 2013

Get file name and extension from URL path

How to get file name with extension in a URL path is relatively straight forward in iOS. 

The code below should work. Put your url into a NSURL variable named yourURL or whatever. Then type the below:

 NSString *JPEGfilename = [[yourURL absoluteString] lastPathComponent];

This will give you your JPEG filename or below:

 NSURL *yourURL = [NSURL urlWithString:@"http://www.hdwallpapers.in/walls/honda_v4_concept_widescreen_bike-wide.jpg"];
 NSString *JPEGfilename = [yourURL lastPathComponent];

Friday, May 10, 2013

Get substring from an NSString in Objective-C

In Objective-C / Cocoa to grab a substring from an NSString based on beginning and ending characters is easy. This is helpful if you want to parse HTML, JSON, or a REST statement returning. See below:


 NSString *sStr = [NSString stringWithFormat:@"%@", assetGroups[indexPath.row]];
 NSString *name= [[[[sStr componentsSeparatedByString:@"Beginning Char(s)"] objectAtIndex:1] componentsSeparatedByString:@"End Char(s)"] objectAtIndex:0]; 
 NSString *newString = [NSString stringWithFormat:@"%@", name];

Tuesday, March 12, 2013

Custom Transition(s) Using QuartzCore

UIStroryBoard when you push view controllers, or segues, it doesn't let you customize too much. What I ended up doing was override the perform method and used QuartzCore Animations to customize our transitions. I subclassed UIStoryBoardSegue and overwrote the perform function.

Below to customize for Push or Pop then for Segues. (For segues remember to change the class to the custom class in IB).

To do it from a normal pop or push (this does cross fade animation, adjust it for yours):


   #import <QuartzCore/QuartzCore.h>


 - (IBAction)launch1990:(id)sender {
    CATransition* transition = [CATransition animation];
    transition.duration = .45;
    transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    transition.type = kCATransitionFade;
    [self.navigationController.view.layer addAnimation:transition forKey:kCATransition];

    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"1990Storyboard" bundle:nil];
    UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:@"1990"];
    [self.navigationController pushViewController:vc animated:NO];
  }
 

To do it from segue:

 
//ZHCustomSegue.h
#import <Foundation/Foundation.h>

@interface ZHCustomSegue : UIStoryboardSegue

@end


//  ZHCustomSegue.m
#import "ZHCustomSegue.h"
#import "QuartzCore/QuartzCore.h"

@implementation ZHCustomSegue


-(void)perform {

    UIViewController *sourceViewController = (UIViewController*)[self sourceViewController];
    UIViewController *destinationController = (UIViewController*)[self destinationViewController];

    CATransition* transition = [CATransition animation];
    transition.duration = .45;
    transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    transition.type = kCATransitionFade; //kCATransitionMoveIn; //, kCATransitionPush,   kCATransitionReveal, kCATransitionFade
   //transition.subtype = kCATransitionFromLeft; //kCATransitionFromLeft, kCATransitionFromRight, kCATransitionFromTop, kCATransitionFromBottom



    [sourceViewController.navigationController.view.layer addAnimation:transition
                                                            forKey:kCATransition];

    [sourceViewController.navigationController pushViewController:destinationController animated:NO];
}

Generating "Always On Top" NSWindow in macOS across all detected displays

Also: Using UIKit & Cocoa Frameworks using Objective-C In m acOS or OS X , written in either Objective-C or Swift  Langues, you m...