an experiment in making a cocoa webkit browser manageable under X11

set window title and url bar text as page loads

+72 -21
+10 -3
WKWindow.h
··· 1 1 #import <Foundation/Foundation.h> 2 - #include <WebKit/WebFrame.h> 3 - #include <WebKit/WebView.h> 2 + #import <WebKit/WebFrame.h> 3 + #import <WebKit/WebView.h> 4 + 5 + #import "WKWindow.h" 6 + #import "X11Window.h" 4 7 5 8 @interface WKWindow : NSWindow 6 9 { 10 + X11Window *shadow; 7 11 NSWindow *window; 8 12 NSScreen *screen; 9 13 NSRect screen_frame; 10 - NSTextField *url; 14 + NSTextField *urlField; 11 15 WebView *browser; 12 16 WebFrame *wframe; 13 17 } 14 18 15 19 - (void)setPosition: (NSArray *)aCoords; 20 + - (void)setShadow: (X11Window *)input; 16 21 - (void)loadURL: (NSString *)url; 22 + - (void)loadURLFromTextField; 23 + - (void)updateProgress; 17 24 18 25 @end
+43 -8
WKWindow.m
··· 1 1 #import "WKWindow.h" 2 + #import "X11Window.h" 2 3 3 4 #include <Cocoa/Cocoa.h> 4 5 ··· 17 18 backing:NSBackingStoreBuffered 18 19 defer:NO 19 20 screen:screen] autorelease]; 20 - [window setBackgroundColor:[NSColor greenColor]]; 21 + [window setBackgroundColor:[NSColor blackColor]]; 21 22 [window setAcceptsMouseMovedEvents:YES]; 22 23 23 24 NSRect bframe = NSMakeRect(0, 0, 300, 300); 24 25 browser = [[WebView alloc] initWithFrame:bframe 25 26 frameName:nil 26 27 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]; 27 38 28 39 [window.contentView addSubview:browser]; 29 40 30 - url = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 270, 300, 30)]; 31 - [window.contentView addSubview:url]; 41 + urlField = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 0, 0)]; 42 + [urlField setTarget:self]; 43 + [urlField setAction:@selector(loadURLFromTextField)]; 44 + [window.contentView addSubview:urlField]; 32 45 33 46 wframe = [browser mainFrame]; 34 47 ··· 37 50 return self; 38 51 } 39 52 53 + /* return key pressed on urlField */ 54 + - (void)loadURLFromTextField 55 + { 56 + [browser takeStringURLFrom:urlField]; 57 + } 58 + 40 59 - (void)loadURL: (NSString *)url 41 60 { 42 - [wframe loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:url]]]; 61 + [wframe loadRequest: 62 + [NSURLRequest requestWithURL:[NSURL URLWithString:url]]]; 63 + } 64 + 65 + /* called while the page is loading, and then again when it finishes */ 66 + - (void)updateProgress 67 + { 68 + [urlField setStringValue:[browser mainFrameURL]]; 69 + [shadow setWindowTitle:[browser mainFrameTitle]]; 43 70 } 44 71 45 72 - (void)setPosition: (NSArray *)aCoords ··· 61 88 62 89 [window setFrame:coords display:true]; 63 90 64 - [url setFrame:NSMakeRect(0, height - 25, width, 25)]; 91 + [urlField setFrame:NSMakeRect(0, height - 23, width, 23)]; 65 92 66 93 /* browser's coordinates are relative to the window */ 67 - [browser setFrame:NSMakeRect(0, 0, width, height - 30)]; 94 + [browser setFrame:NSMakeRect(0, 0, width, height - 24)]; 68 95 69 96 [window makeKeyAndOrderFront:window]; 70 97 } 71 98 99 + - (void)setShadow: (X11Window *)input 100 + { 101 + [shadow autorelease]; 102 + shadow = [input retain]; 103 + } 104 + 72 105 /* these are needed because setting styleMask to NSBorderlessWindowMask turns 73 106 * them off */ 74 - - (BOOL)canBecomeKeyWindow { 107 + - (BOOL)canBecomeKeyWindow 108 + { 75 109 return YES; 76 110 } 77 111 78 - - (BOOL)canBecomeMainWindow { 112 + - (BOOL)canBecomeMainWindow 113 + { 79 114 return YES; 80 115 } 81 116
+1
X11Window.h
··· 11 11 12 12 - (void)updateWKWindowPosition; 13 13 - (void)mainLoopWithWKWindow: (id)wkwobj; 14 + - (void)setWindowTitle:(NSString *)title; 14 15 - (void)sendKeyFromXEvent:(XEvent)e; 15 16 16 17 @end
+12 -7
X11Window.m
··· 17 17 18 18 - (id)init 19 19 { 20 - XTextProperty win_name_prop; 21 - char *win_name = "shadowebkit"; 22 - 23 20 self = [super init]; 24 21 25 22 display = XOpenDisplay(NULL); ··· 34 31 BlackPixel(display, screen) 35 32 ); 36 33 37 - if (XStringListToTextProperty(&win_name, 1, &win_name_prop) == 0) 38 - errx(1, "XStringListToTextProperty"); 39 - 40 - XSetWMName(display, window, &win_name_prop); 34 + [self setWindowTitle:@"shadowebkit"]; 41 35 42 36 XMapWindow(display, window); 43 37 XSelectInput(display, window, KeyPressMask | KeyReleaseMask | ··· 68 62 } 69 63 70 64 [pool release]; 65 + } 66 + 67 + - (void)setWindowTitle:(NSString *)title 68 + { 69 + XTextProperty winNameProp; 70 + const char *winName = [title UTF8String]; 71 + 72 + if (XStringListToTextProperty(&winName, 1, &winNameProp) == 0) 73 + errx(1, "XStringListToTextProperty"); 74 + 75 + XSetWMName(display, window, &winNameProp); 71 76 } 72 77 73 78 - (void)updateWKWindowPosition
+6 -3
main.m
··· 28 28 argc -= optind; 29 29 argv += optind; 30 30 31 + /* bring up the X11 window */ 32 + X11Window *X = [X11Window alloc]; 33 + [X init]; 34 + 31 35 /* handle webkit window in the main thread (webkit won't allow use in 32 36 * another thread anyway) */ 33 37 WKWindow *WKW = [WKWindow alloc]; 34 38 [WKW init]; 39 + [WKW setShadow:X]; 35 40 36 - /* bring up the X11 window in its own thread */ 37 - X11Window *X = [X11Window alloc]; 38 - [X init]; 41 + /* let X do its event loop in its own thread */ 39 42 [X performSelectorInBackground:@selector(mainLoopWithWKWindow:) 40 43 withObject:WKW]; 41 44