/* * Copyright 2011 Sven Weidauer * * This file is part of NetSurf, http://www.netsurf-browser.org/ * * NetSurf is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 of the License. * * NetSurf 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #import "utils/nsoption.h" #import "utils/corestrings.h" #import "utils/filename.h" #import "utils/file.h" #import "utils/messages.h" #import "utils/nsurl.h" #import "netsurf/content.h" #import "netsurf/browser_window.h" #import "desktop/browser_history.h" #import "cocoa/gui.h" #import "cocoa/BrowserViewController.h" #import "cocoa/BrowserView.h" #import "cocoa/BrowserWindowController.h" #import "cocoa/fetch.h" @implementation BrowserViewController @synthesize browser; @synthesize url; @synthesize browserView; @synthesize windowController; @synthesize title; @synthesize status; @synthesize isProcessing; @synthesize favicon; @synthesize canGoBack; @synthesize canGoForward; - (instancetype)initWithBrowser:(struct browser_window *)bw { if ((self = [super initWithNibName:@"Browser" bundle:nil]) == nil) { return nil; } browser = bw; return self; } - (IBAction)navigate:(id)sender { nsurl *urlns; nserror error; error = nsurl_create([url UTF8String], &urlns); if (error != NSERROR_OK) { cocoa_warning(messages_get_errorcode(error), 0); } else { browser_window_navigate(browser, urlns, NULL, BW_NAVIGATE_HISTORY, NULL, NULL, NULL); nsurl_unref(urlns); } } - (void)awakeFromNib { [browserView setBrowser:browser]; } - (IBAction)zoomIn:(id)sender { browser_window_set_scale(browser, browser_window_get_scale(browser) * 1.1, true); } - (IBAction)zoomOut:(id)sender { browser_window_set_scale(browser, browser_window_get_scale(browser) * 0.9, true); } - (IBAction)zoomOriginal:(id)sender { browser_window_set_scale(browser, (float)nsoption_int(scale) / 100.0, true); } - (IBAction)backForwardSelected:(id)sender { if ([sender selectedSegment] == 0) { [self goBack:sender]; } else { [self goForward:sender]; } } - (IBAction)goBack:(id)sender { if (browser && browser_window_history_back_available(browser)) { browser_window_history_back(browser, false); [self updateBackForward]; } } - (IBAction)goForward:(id)sender { if (browser && browser_window_history_forward_available(browser)) { browser_window_history_forward(browser, false); [self updateBackForward]; } } - (IBAction)goHome:(id)sender { nsurl *urlns; nserror error; error = nsurl_create(nsoption_charp(homepage_url), &urlns); if (error == NSERROR_OK) { error = browser_window_navigate(browser, urlns, NULL, BW_NAVIGATE_HISTORY, NULL, NULL, NULL); nsurl_unref(urlns); } if (error != NSERROR_OK) { cocoa_warning(messages_get_errorcode(error), 0); } } - (IBAction)reloadPage:(id)sender { browser_window_reload(browser, true); } - (IBAction)stopLoading:(id)sender { browser_window_stop(browser); } - (IBAction)viewSource:(id)sender { struct hlcache_handle *content; size_t size; const char *source; char *path = NULL; if (browser == NULL) { return; } content = browser_window_get_content(browser); if (content == NULL) { return; } source = content_get_source_data(content, &size); if (source == NULL) { return; } /* try to load local files directly. */ netsurf_nsurl_to_path(hlcache_handle_get_url(content), &path); if (path == NULL) { /* We cannot release the requested filename until after it * has finished being used. As we can't easily find out when * this is, we simply don't bother releasing it and simply * allow it to be re-used next time NetSurf is started. The * memory overhead from doing this is under 1 byte per * filename. */ const char *filename = filename_request(); const char *extension = "txt"; fprintf(stderr, "filename '%p'\n", filename); if (filename == NULL) return; lwc_string *str = content_get_mime_type(content); if (str) { NSString *mime = [NSString stringWithUTF8String:lwc_string_data(str)]; NSString *uti = (__bridge_transfer NSString *)UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, (__bridge CFStringRef)mime, NULL); NSString *ext = (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)uti, kUTTagClassFilenameExtension); extension = [ext UTF8String]; lwc_string_unref(str); } NSURL *dataUrl = [NSURL URLWithString:[NSString stringWithFormat:@"%s.%s", filename, extension] relativeToURL:[NSURL fileURLWithPath:@TEMP_FILENAME_PREFIX]]; NSData *data = [NSData dataWithBytes:source length:size]; [data writeToURL:dataUrl atomically:NO]; path = (char *)[[dataUrl path] UTF8String]; } if (path) { NSString *p = [NSString stringWithUTF8String:path]; NSWorkspace *ws = [NSWorkspace sharedWorkspace]; [ws openFile:p withApplication:@"Xcode"]; } } static inline bool compare_float(float a, float b) { const float epsilon = 0.00001; if (a == b) { return true; } return fabs((a - b) / b) <= epsilon; } - (BOOL)validateUserInterfaceItem:(id)item { SEL action = [item action]; if (action == @selector(copy:)) { return browser_window_get_editor_flags(browser) & BW_EDITOR_CAN_COPY; } if (action == @selector(cut:)) { return browser_window_get_editor_flags(browser) & BW_EDITOR_CAN_CUT; } if (action == @selector(paste:)) { return browser_window_get_editor_flags(browser) & BW_EDITOR_CAN_PASTE; } if (action == @selector(stopLoading:)) { return browser_window_stop_available(browser); } if (action == @selector(zoomOriginal:)) { return !compare_float(browser_window_get_scale(browser), (float)nsoption_int(scale) / 100.0); } if (action == @selector(goBack:)) { return canGoBack; } if (action == @selector(goForward:)) { return canGoForward; } return YES; } - (void)updateBackForward { [browserView updateHistory]; [self setCanGoBack:browser != NULL && browser_window_history_back_available(browser)]; [self setCanGoForward:browser != NULL && browser_window_history_forward_available(browser)]; } - (void)contentUpdated { [browserView updateHistory]; } struct history_add_menu_item_data { NSInteger index; void *menu; void *target; }; static NSMenu *get_menu(const struct history_add_menu_item_data *data) { return (__bridge NSMenu *)data->menu; } static id get_target(const struct history_add_menu_item_data *data) { return (__bridge id)data->target; } static bool history_add_menu_item_cb(const struct browser_window *bw, int x0, int y0, int x1, int y1, const struct history_entry *page, void *user_data) { struct history_add_menu_item_data *data = user_data; NSMenuItem *item = nil; if (data->index < [get_menu(data) numberOfItems]) { item = [get_menu(data) itemAtIndex:data->index]; } else { item = [[NSMenuItem alloc] initWithTitle:@"" action:@selector(historyItemSelected:) keyEquivalent:@""]; [get_menu(data) addItem:item]; } ++data->index; [item setTarget:get_target(data)]; [item setTitle:[NSString stringWithUTF8String:browser_window_history_entry_get_title(page)]]; [item setRepresentedObject:[NSValue valueWithPointer:page]]; return true; } - (IBAction)historyItemSelected:(id)sender { struct history_entry *entry = [[sender representedObject] pointerValue]; browser_window_history_go(browser, entry, false); [self updateBackForward]; } - (void)buildBackMenu:(NSMenu *)menu { struct history_add_menu_item_data data = { .index = 0, .menu = (__bridge void *)menu, .target = (__bridge void *)self }; browser_window_history_enumerate_back(browser, history_add_menu_item_cb, &data); while (data.index < [menu numberOfItems]) { [menu removeItemAtIndex:data.index]; } } - (void)buildForwardMenu:(NSMenu *)menu { struct history_add_menu_item_data data = { .index = 0, .menu = (__bridge void *)menu, .target = (__bridge void *)self }; browser_window_history_enumerate_forward(browser, history_add_menu_item_cb, &data); while (data.index < [menu numberOfItems]) { [menu removeItemAtIndex:data.index]; } } @end