an experiment in making a cocoa webkit browser manageable under X11

add a status bar, show resource loading status

+121 -25
+13 -4
WKWindow.h
··· 12 12 NSScreen *screen; 13 13 NSRect screen_frame; 14 14 NSTextField *urlField; 15 + NSTextField *statusBar; 15 16 WebView *browser; 16 17 WebFrame *wframe; 18 + 19 + NSURL *currentURL; 20 + 21 + int resourceCount; 22 + int resourceCompletedCount; 23 + int resourceFailedCount; 17 24 } 18 25 19 - - (void)setPosition: (NSArray *)aCoords; 20 - - (void)setShadow: (X11Window *)input; 21 - - (void)loadURL: (NSString *)url; 26 + - (void)setPosition:(NSArray *)aCoords; 27 + - (void)setShadow:(X11Window *)input; 28 + - (void)setStatus:(NSString *)text; 29 + - (void)setStatusToResourceCounts; 30 + - (void)setTitle:(NSString *)text; 31 + - (void)loadURL:(NSString *)url; 22 32 - (void)loadURLFromTextField; 23 - - (void)updateProgress; 24 33 25 34 @end
+108 -21
WKWindow.m
··· 21 21 [window setBackgroundColor:[NSColor blackColor]]; 22 22 [window setAcceptsMouseMovedEvents:YES]; 23 23 24 + currentURL = [[NSURL alloc] init]; 25 + 24 26 NSRect bframe = NSMakeRect(0, 0, 300, 300); 25 27 browser = [[WebView alloc] initWithFrame:bframe 26 28 frameName:nil 27 29 groupName:nil]; 28 - 29 - /* setup callbacks to update the url and title */ 30 - [[NSNotificationCenter defaultCenter] addObserver:self 31 - selector:@selector(updateProgress) 32 - name:WebViewProgressStartedNotification 33 - object:nil]; 34 - [[NSNotificationCenter defaultCenter] addObserver:self 35 - selector:@selector(updateProgress) 36 - name:WebViewProgressFinishedNotification 37 - object:nil]; 38 - 30 + [browser setGroupName:@"shadowebkit"]; 31 + [browser setUIDelegate:self]; 32 + [browser setResourceLoadDelegate:self]; 33 + [browser setFrameLoadDelegate:self]; 39 34 [window.contentView addSubview:browser]; 40 35 41 36 urlField = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 0, 0)]; ··· 43 38 [urlField setAction:@selector(loadURLFromTextField)]; 44 39 [window.contentView addSubview:urlField]; 45 40 41 + statusBar = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 0, 0)]; 42 + [statusBar setTarget:self]; 43 + [statusBar setEditable:false]; 44 + [statusBar setSelectable:false]; 45 + [statusBar setBordered:false]; 46 + [statusBar setTextColor:[NSColor lightGrayColor]]; 47 + [statusBar setBackgroundColor:[NSColor blackColor]]; 48 + [self setStatus:@""]; 49 + [window.contentView addSubview:statusBar]; 50 + 46 51 wframe = [browser mainFrame]; 47 52 48 53 [window makeKeyAndOrderFront:window]; ··· 56 61 [self loadURL:[urlField stringValue]]; 57 62 } 58 63 59 - - (void)loadURL: (NSString *)url 64 + - (void)loadURL:(NSString *)url 60 65 { 61 66 NSURL *u = [NSURL URLWithString:url]; 62 67 ··· 67 72 [wframe loadRequest:[NSURLRequest requestWithURL:u]]; 68 73 } 69 74 70 - /* called while the page is loading, and then again when it finishes */ 71 - - (void)updateProgress 72 - { 73 - [urlField setStringValue:[browser mainFrameURL]]; 74 - [shadow setWindowTitle:[browser mainFrameTitle]]; 75 - } 76 - 77 - - (void)setPosition: (NSArray *)aCoords 75 + - (void)setPosition:(NSArray *)aCoords 78 76 { 79 77 int x = [[aCoords objectAtIndex:0] intValue]; 80 78 int y = [[aCoords objectAtIndex:1] intValue]; ··· 96 94 [urlField setFrame:NSMakeRect(0, height - 23, width, 23)]; 97 95 98 96 /* browser's coordinates are relative to the window */ 99 - [browser setFrame:NSMakeRect(0, 0, width, height - 24)]; 97 + [browser setFrame:NSMakeRect(0, 17, width, height - 17 - 24)]; 98 + 99 + [statusBar setFrame:NSMakeRect(0, 0, width, 17)]; 100 100 101 101 [window makeKeyAndOrderFront:window]; 102 102 } ··· 107 107 shadow = [input retain]; 108 108 } 109 109 110 + - (void)setStatus:(NSString *)text 111 + { 112 + [statusBar setStringValue:text]; 113 + } 114 + 115 + - (void)setStatusToResourceCounts 116 + { 117 + if (resourceCompletedCount + resourceFailedCount >= resourceCount) 118 + [self setStatus:@""]; 119 + else 120 + [self setStatus:[NSString 121 + stringWithFormat:@"Loading \"%@\", completed %d of %d item%s", 122 + [currentURL absoluteString], resourceCompletedCount, 123 + resourceCount, (resourceCount == 1 ? "" : "s")]]; 124 + } 125 + 126 + - (void)setTitle:(NSString *)text 127 + { 128 + [shadow setWindowTitle:text]; 129 + } 130 + 110 131 /* these are needed because setting styleMask to NSBorderlessWindowMask turns 111 132 * them off */ 112 133 - (BOOL)canBecomeKeyWindow ··· 118 139 { 119 140 return YES; 120 141 } 142 + 143 + 144 + /* WebFrameLoadDelegate glue */ 145 + 146 + - (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame 147 + { 148 + if (frame != [sender mainFrame]) 149 + return; 150 + 151 + [self setStatus:@""]; 152 + } 153 + 154 + - (void)webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame 155 + { 156 + if (frame != [sender mainFrame]) 157 + return; 158 + 159 + [self setTitle:title]; 160 + } 161 + 162 + - (void)webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame 163 + { 164 + if (frame != [sender mainFrame]) 165 + return; 166 + 167 + currentURL = [[NSURL URLWithString:[[[[frame provisionalDataSource] 168 + request] URL] absoluteString]] retain]; 169 + 170 + resourceCount = 0; 171 + resourceCompletedCount = 0; 172 + resourceFailedCount = 0; 173 + 174 + [urlField setStringValue:[currentURL absoluteString]]; 175 + [self setStatus:[NSString stringWithFormat:@"Loading \"%@\"...", 176 + [currentURL absoluteString]]]; 177 + } 178 + 179 + 180 + /* WebResourceLoadDelegate glue */ 181 + 182 + - (id)webView:(WebView *)sender identifierForInitialRequest:(NSURLRequest *)request fromDataSource:(WebDataSource *)dataSource 183 + { 184 + return [NSNumber numberWithInt:resourceCount++]; 185 + } 186 + 187 + - (NSURLRequest *)webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponsefromDataSource:(WebDataSource *)dataSource 188 + { 189 + /* TODO: implement an ad blocker here? */ 190 + [self setStatusToResourceCounts]; 191 + return request; 192 + } 193 + 194 + - (void)webView:(WebView *)sender resource:(id)identifier didFailLoadingWithError:(NSError *)error fromDataSource:(WebDataSource *)dataSource 195 + { 196 + resourceFailedCount++; 197 + [self setStatusToResourceCounts]; 198 + } 199 + 200 + - (void)webView:(WebView *)sender resource:(id)identifier didFinishLoadingFromDataSource:(WebDataSource *)dataSource 201 + { 202 + resourceCompletedCount++; 203 + [self setStatusToResourceCounts]; 204 + } 205 + 206 + /* WebUIDelegate glue */ 207 + 121 208 122 209 @end