github.com/secoba/wails/v2@v2.6.4/internal/frontend/desktop/darwin/Application.m (about)

     1  //go:build darwin
     2  //
     3  //  Application.m
     4  //
     5  //  Created by Lea Anthony on 10/10/21.
     6  //
     7  
     8  #import <Foundation/Foundation.h>
     9  #import <Cocoa/Cocoa.h>
    10  #import "WailsContext.h"
    11  #import "Application.h"
    12  #import "ApDelegate.h"
    13  #import "WindowDelegate.h"
    14  #import "WailsMenu.h"
    15  #import "WailsMenuItem.h"
    16  
    17  WailsContext* Create(const char* title, int width, int height, int frameless, int resizable, int fullscreen, int fullSizeContent, int hideTitleBar, int titlebarAppearsTransparent, int hideTitle, int useToolbar, int hideToolbarSeparator, int webviewIsTransparent, int alwaysOnTop, int hideWindowOnClose, const char *appearance, int windowIsTranslucent, int devtoolsEnabled, int defaultContextMenuEnabled, int windowStartState, int startsHidden, int minWidth, int minHeight, int maxWidth, int maxHeight, bool fraudulentWebsiteWarningEnabled, struct Preferences preferences, int singleInstanceLockEnabled, const char* singleInstanceUniqueId) {
    18  
    19      [NSApplication sharedApplication];
    20  
    21      WailsContext *result = [WailsContext new];
    22  
    23      result.devtoolsEnabled = devtoolsEnabled;
    24      result.defaultContextMenuEnabled = defaultContextMenuEnabled;
    25  
    26      if ( windowStartState == WindowStartsFullscreen ) {
    27          fullscreen = 1;
    28      }
    29  
    30      [result CreateWindow:width :height :frameless :resizable :fullscreen :fullSizeContent :hideTitleBar :titlebarAppearsTransparent :hideTitle :useToolbar :hideToolbarSeparator :webviewIsTransparent :hideWindowOnClose :safeInit(appearance) :windowIsTranslucent :minWidth :minHeight :maxWidth :maxHeight :fraudulentWebsiteWarningEnabled :preferences];
    31      [result SetTitle:safeInit(title)];
    32      [result Center];
    33  
    34      switch( windowStartState ) {
    35          case WindowStartsMaximised:
    36              [result.mainWindow zoom:nil];
    37              break;
    38          case WindowStartsMinimised:
    39              //TODO: Can you start a mac app minimised?
    40              break;
    41      }
    42  
    43      if ( startsHidden == 1 ) {
    44          result.startHidden = true;
    45      }
    46  
    47      if ( fullscreen == 1 ) {
    48          result.startFullscreen = true;
    49      }
    50  
    51      if ( singleInstanceLockEnabled == 1 ) {
    52          result.singleInstanceLockEnabled = true;
    53          result.singleInstanceUniqueId = safeInit(singleInstanceUniqueId);
    54      }
    55  
    56      result.alwaysOnTop = alwaysOnTop;
    57      result.hideOnClose = hideWindowOnClose;
    58  
    59      return result;
    60  }
    61  
    62  void ExecJS(void* inctx, const char *script) {
    63      WailsContext *ctx = (__bridge WailsContext*) inctx;
    64      NSString *nsscript = safeInit(script);
    65      ON_MAIN_THREAD(
    66         [ctx ExecJS:nsscript];
    67         [nsscript release];
    68      );
    69  }
    70  
    71  void SetTitle(void* inctx, const char *title) {
    72      WailsContext *ctx = (__bridge WailsContext*) inctx;
    73      NSString *_title = safeInit(title);
    74      ON_MAIN_THREAD(
    75         [ctx SetTitle:_title];
    76      );
    77  }
    78  
    79  
    80  void SetBackgroundColour(void *inctx, int r, int g, int b, int a) {
    81      WailsContext *ctx = (__bridge WailsContext*) inctx;
    82      ON_MAIN_THREAD(
    83         [ctx SetBackgroundColour:r :g :b :a];
    84      );
    85  }
    86  
    87  void SetSize(void* inctx, int width, int height) {
    88      WailsContext *ctx = (__bridge WailsContext*) inctx;
    89      ON_MAIN_THREAD(
    90         [ctx SetSize:width :height];
    91      );
    92  }
    93  
    94  void SetAlwaysOnTop(void* inctx, int onTop) {
    95      WailsContext *ctx = (__bridge WailsContext*) inctx;
    96      ON_MAIN_THREAD(
    97         [ctx SetAlwaysOnTop:onTop];
    98      );
    99  }
   100  
   101  void SetMinSize(void* inctx, int width, int height) {
   102      WailsContext *ctx = (__bridge WailsContext*) inctx;
   103      ON_MAIN_THREAD(
   104         [ctx SetMinSize:width :height];
   105      );
   106  }
   107  
   108  void SetMaxSize(void* inctx, int width, int height) {
   109      WailsContext *ctx = (__bridge WailsContext*) inctx;
   110      ON_MAIN_THREAD(
   111         [ctx SetMaxSize:width :height];
   112      );
   113  }
   114  
   115  void SetPosition(void* inctx, int x, int y) {
   116      WailsContext *ctx = (__bridge WailsContext*) inctx;
   117      ON_MAIN_THREAD(
   118         [ctx SetPosition:x :y];
   119      );
   120  }
   121  
   122  void Center(void* inctx) {
   123      WailsContext *ctx = (__bridge WailsContext*) inctx;
   124      ON_MAIN_THREAD(
   125         [ctx Center];
   126      );
   127  }
   128  
   129  void Fullscreen(void* inctx) {
   130      WailsContext *ctx = (__bridge WailsContext*) inctx;
   131      ON_MAIN_THREAD(
   132         [ctx Fullscreen];
   133      );
   134  }
   135  
   136  void UnFullscreen(void* inctx) {
   137      WailsContext *ctx = (__bridge WailsContext*) inctx;
   138      ON_MAIN_THREAD(
   139         [ctx UnFullscreen];
   140      );
   141  }
   142  
   143  void Minimise(void* inctx) {
   144      WailsContext *ctx = (__bridge WailsContext*) inctx;
   145      ON_MAIN_THREAD(
   146         [ctx Minimise];
   147      );
   148  }
   149  
   150  void UnMinimise(void* inctx) {
   151      WailsContext *ctx = (__bridge WailsContext*) inctx;
   152      ON_MAIN_THREAD(
   153         [ctx UnMinimise];
   154      );
   155  }
   156  
   157  void Maximise(void* inctx) {
   158      WailsContext *ctx = (__bridge WailsContext*) inctx;
   159      ON_MAIN_THREAD(
   160         [ctx Maximise];
   161      );
   162  }
   163  
   164  void ToggleMaximise(void* inctx) {
   165      WailsContext *ctx = (__bridge WailsContext*) inctx;
   166      ON_MAIN_THREAD(
   167         [ctx ToggleMaximise];
   168      );
   169  }
   170  
   171  const char* GetSize(void *inctx) {
   172      WailsContext *ctx = (__bridge WailsContext*) inctx;
   173      NSRect frame = [ctx.mainWindow frame];
   174      NSString *result = [NSString stringWithFormat:@"%d,%d", (int)frame.size.width, (int)frame.size.height];
   175      return [result UTF8String];
   176  }
   177  
   178  const char* GetPosition(void *inctx) {
   179      WailsContext *ctx = (__bridge WailsContext*) inctx;
   180      NSScreen* screen = [ctx getCurrentScreen];
   181      NSRect windowFrame = [ctx.mainWindow frame];
   182      NSRect screenFrame = [screen visibleFrame];
   183      int x = windowFrame.origin.x - screenFrame.origin.x;
   184      int y = windowFrame.origin.y - screenFrame.origin.y;
   185      y = screenFrame.size.height - y - windowFrame.size.height;
   186      NSString *result = [NSString stringWithFormat:@"%d,%d",x,y];
   187      return [result UTF8String];
   188  }
   189  
   190  const bool IsFullScreen(void *inctx) {
   191      WailsContext *ctx = (__bridge WailsContext*) inctx;
   192      return [ctx IsFullScreen];
   193  }
   194  
   195  const bool IsMinimised(void *inctx) {
   196      WailsContext *ctx = (__bridge WailsContext*) inctx;
   197      return [ctx IsMinimised];
   198  }
   199  
   200  const bool IsMaximised(void *inctx) {
   201      WailsContext *ctx = (__bridge WailsContext*) inctx;
   202      return [ctx IsMaximised];
   203  }
   204  
   205  void UnMaximise(void* inctx) {
   206      WailsContext *ctx = (__bridge WailsContext*) inctx;
   207      ON_MAIN_THREAD(
   208         [ctx UnMaximise];
   209      );
   210  }
   211  
   212  void Quit(void *inctx) {
   213      WailsContext *ctx = (__bridge WailsContext*) inctx;
   214      [NSApp stop:ctx];
   215      [NSApp abortModal];
   216  }
   217  
   218  void Hide(void *inctx) {
   219      WailsContext *ctx = (__bridge WailsContext*) inctx;
   220      ON_MAIN_THREAD(
   221         [ctx Hide];
   222      );
   223  }
   224  
   225  void Show(void *inctx) {
   226      WailsContext *ctx = (__bridge WailsContext*) inctx;
   227      ON_MAIN_THREAD(
   228         [ctx Show];
   229      );
   230  }
   231  
   232  
   233  void HideApplication(void *inctx) {
   234      WailsContext *ctx = (__bridge WailsContext*) inctx;
   235      ON_MAIN_THREAD(
   236         [ctx HideApplication];
   237      );
   238  }
   239  
   240  void ShowApplication(void *inctx) {
   241      WailsContext *ctx = (__bridge WailsContext*) inctx;
   242      ON_MAIN_THREAD(
   243         [ctx ShowApplication];
   244      );
   245  }
   246  
   247  NSString* safeInit(const char* input) {
   248      NSString *result = nil;
   249      if (input != nil) {
   250          result = [NSString stringWithUTF8String:input];
   251      }
   252      return result;
   253  }
   254  
   255  void MessageDialog(void *inctx, const char* dialogType, const char* title, const char* message, const char* button1, const char* button2, const char* button3, const char* button4, const char* defaultButton, const char* cancelButton, void* iconData, int iconDataLength) {
   256      WailsContext *ctx = (__bridge WailsContext*) inctx;
   257  
   258      NSString *_dialogType = safeInit(dialogType);
   259      NSString *_title = safeInit(title);
   260      NSString *_message = safeInit(message);
   261      NSString *_button1 = safeInit(button1);
   262      NSString *_button2 = safeInit(button2);
   263      NSString *_button3 = safeInit(button3);
   264      NSString *_button4 = safeInit(button4);
   265      NSString *_defaultButton = safeInit(defaultButton);
   266      NSString *_cancelButton = safeInit(cancelButton);
   267  
   268      ON_MAIN_THREAD(
   269                     [ctx MessageDialog:_dialogType :_title :_message :_button1 :_button2 :_button3 :_button4 :_defaultButton :_cancelButton :iconData :iconDataLength];
   270      )
   271  }
   272  
   273  void OpenFileDialog(void *inctx, const char* title, const char* defaultFilename, const char* defaultDirectory, int allowDirectories, int allowFiles, int canCreateDirectories, int treatPackagesAsDirectories, int resolveAliases, int showHiddenFiles, int allowMultipleSelection, const char* filters) {
   274  
   275      WailsContext *ctx = (__bridge WailsContext*) inctx;
   276      NSString *_title = safeInit(title);
   277      NSString *_defaultFilename = safeInit(defaultFilename);
   278      NSString *_defaultDirectory = safeInit(defaultDirectory);
   279      NSString *_filters = safeInit(filters);
   280  
   281      ON_MAIN_THREAD(
   282                     [ctx OpenFileDialog:_title :_defaultFilename :_defaultDirectory :allowDirectories :allowFiles :canCreateDirectories :treatPackagesAsDirectories :resolveAliases :showHiddenFiles :allowMultipleSelection :_filters];
   283      )
   284  }
   285  
   286  void SaveFileDialog(void *inctx, const char* title, const char* defaultFilename, const char* defaultDirectory, int canCreateDirectories, int treatPackagesAsDirectories, int showHiddenFiles, const char* filters) {
   287  
   288      WailsContext *ctx = (__bridge WailsContext*) inctx;
   289      NSString *_title = safeInit(title);
   290      NSString *_defaultFilename = safeInit(defaultFilename);
   291      NSString *_defaultDirectory = safeInit(defaultDirectory);
   292      NSString *_filters = safeInit(filters);
   293  
   294      ON_MAIN_THREAD(
   295                     [ctx SaveFileDialog:_title :_defaultFilename :_defaultDirectory :canCreateDirectories :treatPackagesAsDirectories :showHiddenFiles :_filters];
   296      )
   297  }
   298  
   299  void AppendRole(void *inctx, void *inMenu, int role) {
   300      WailsContext *ctx = (__bridge WailsContext*) inctx;
   301      WailsMenu *menu = (__bridge WailsMenu*) inMenu;
   302      [menu appendRole :ctx :role];
   303  }
   304  
   305  void* NewMenu(const char *name) {
   306      NSString *title = @"";
   307      if (name != nil) {
   308          title = [NSString stringWithUTF8String:name];
   309      }
   310      WailsMenu *result = [[WailsMenu new] initWithNSTitle:title];
   311      return result;
   312  }
   313  
   314  void AppendSubmenu(void* inparent, void* inchild) {
   315      WailsMenu *parent = (__bridge WailsMenu*) inparent;
   316      WailsMenu *child = (__bridge WailsMenu*) inchild;
   317      [parent appendSubmenu:child];
   318  }
   319  
   320  void SetAsApplicationMenu(void *inctx, void *inMenu) {
   321      WailsContext *ctx = (__bridge WailsContext*) inctx;
   322      WailsMenu *menu = (__bridge WailsMenu*) inMenu;
   323      ctx.applicationMenu = menu;
   324  }
   325  
   326  void UpdateApplicationMenu(void *inctx) {
   327      WailsContext *ctx = (__bridge WailsContext*) inctx;
   328      ON_MAIN_THREAD(
   329                     NSApplication *app = [NSApplication sharedApplication];
   330                     [app setMainMenu:ctx.applicationMenu];
   331      )
   332  }
   333  
   334  void SetAbout(void *inctx, const char* title, const char* description, void* imagedata, int datalen) {
   335      WailsContext *ctx = (__bridge WailsContext*) inctx;
   336      NSString *_title = safeInit(title);
   337      NSString *_description = safeInit(description);
   338  
   339      [ctx SetAbout :_title :_description :imagedata :datalen];
   340  }
   341  
   342  void* AppendMenuItem(void* inctx, void* inMenu, const char* label, const char* shortcutKey, int modifiers, int disabled, int checked, int menuItemID) {
   343      WailsContext *ctx = (__bridge WailsContext*) inctx;
   344      WailsMenu *menu = (__bridge WailsMenu*) inMenu;
   345      NSString *_label = safeInit(label);
   346      NSString *_shortcutKey = safeInit(shortcutKey);
   347  
   348      return [menu AppendMenuItem:ctx :_label :_shortcutKey :modifiers :disabled :checked :menuItemID];
   349  }
   350  
   351  void UpdateMenuItem(void* nsmenuitem, int checked) {
   352      ON_MAIN_THREAD(
   353          WailsMenuItem *menuItem = (__bridge WailsMenuItem*) nsmenuitem;
   354          [menuItem setState:(checked == 1?NSControlStateValueOn:NSControlStateValueOff)];
   355                     )
   356  }
   357  
   358  
   359  void AppendSeparator(void* inMenu) {
   360      WailsMenu *menu = (__bridge WailsMenu*) inMenu;
   361      [menu AppendSeparator];
   362  }
   363  
   364  
   365  
   366  void Run(void *inctx, const char* url) {
   367      WailsContext *ctx = (__bridge WailsContext*) inctx;
   368      NSApplication *app = [NSApplication sharedApplication];
   369      ApDelegate* delegate = [ApDelegate new];
   370      [app setDelegate:(id)delegate];
   371      ctx.appdelegate = delegate;
   372      delegate.mainWindow = ctx.mainWindow;
   373      delegate.alwaysOnTop = ctx.alwaysOnTop;
   374      delegate.startHidden = ctx.startHidden;
   375      delegate.singleInstanceLockEnabled = ctx.singleInstanceLockEnabled;
   376      delegate.singleInstanceUniqueId = ctx.singleInstanceUniqueId;
   377      delegate.startFullscreen = ctx.startFullscreen;
   378  
   379      NSString *_url = safeInit(url);
   380      [ctx loadRequest:_url];
   381      [_url release];
   382  
   383      [app setMainMenu:ctx.applicationMenu];
   384  }
   385  
   386  void RunMainLoop(void) {
   387      NSApplication *app = [NSApplication sharedApplication];
   388      [app run];
   389  }
   390  
   391  void ReleaseContext(void *inctx) {
   392      WailsContext *ctx = (__bridge WailsContext*) inctx;
   393      [ctx release];
   394  }
   395  
   396  // Credit: https://stackoverflow.com/q/33319295
   397  void WindowPrint(void *inctx) {
   398  
   399  	// Check if macOS 11.0 or newer
   400  	if (@available(macOS 11.0, *)) {
   401          ON_MAIN_THREAD(
   402              WailsContext *ctx = (__bridge WailsContext*) inctx;
   403              WKWebView* webView = ctx.webview;
   404  
   405              // I think this should be exposed as a config
   406              // It directly affects the printed output/PDF
   407              NSPrintInfo *pInfo = [NSPrintInfo sharedPrintInfo];
   408              pInfo.horizontalPagination = NSPrintingPaginationModeAutomatic;
   409              pInfo.verticalPagination = NSPrintingPaginationModeAutomatic;
   410              pInfo.verticallyCentered = YES;
   411              pInfo.horizontallyCentered = YES;
   412              pInfo.orientation = NSPaperOrientationLandscape;
   413              pInfo.leftMargin = 0;
   414              pInfo.rightMargin = 0;
   415              pInfo.topMargin = 0;
   416              pInfo.bottomMargin = 0;
   417  
   418              NSPrintOperation *po = [webView printOperationWithPrintInfo:pInfo];
   419              po.showsPrintPanel = YES;
   420              po.showsProgressPanel = YES;
   421  
   422              po.view.frame = webView.bounds;
   423  
   424              [po runOperationModalForWindow:ctx.mainWindow delegate:ctx.mainWindow.delegate didRunSelector:nil contextInfo:nil];
   425          )
   426  	}
   427  }