From 3fdc4622a767c714139fefe9fa74e644836d3e91 Mon Sep 17 00:00:00 2001
From: "avi@chromium.org"
 <avi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>
Date: Thu, 6 Oct 2011 22:25:49 +0000
Subject: Initial changes for Mac content shell.

BUG=90445
TEST=none

Committed: http://src.chromium.org/viewvc/chrome?view=rev&revision=104359

Review URL: http://codereview.chromium.org/8171012

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@104379 0039d316-1c4b-4281-b951-d872f2087c98
---
 content/shell/shell.cc     |   4 +-
 content/shell/shell.h      |   8 +-
 content/shell/shell_gtk.cc |   2 +-
 content/shell/shell_mac.mm | 189 +++++++++++++++++++++++++++++++++++++++++++--
 content/shell/shell_win.cc |  26 +++----
 5 files changed, 202 insertions(+), 27 deletions(-)

(limited to 'content')

diff --git a/content/shell/shell.cc b/content/shell/shell.cc
index 3e3801b..65eb1ea 100644
--- a/content/shell/shell.cc
+++ b/content/shell/shell.cc
@@ -50,9 +50,7 @@ Shell* Shell::CreateNewWindow(content::BrowserContext* browser_context,
                               int routing_id,
                               TabContents* base_tab_contents) {
   Shell* shell = new Shell();
-  shell->PlatformCreateWindow();
-
-  shell->PlatformSizeTo(kTestWindowWidth, kTestWindowHeight);
+  shell->PlatformCreateWindow(kTestWindowWidth, kTestWindowHeight);
 
   shell->tab_contents_.reset(new TabContents(
       browser_context,
diff --git a/content/shell/shell.h b/content/shell/shell.h
index c95c929..99d5748 100644
--- a/content/shell/shell.h
+++ b/content/shell/shell.h
@@ -55,6 +55,12 @@ class Shell : public TabContentsDelegate {
 
   TabContents* tab_contents() const { return tab_contents_.get(); }
 
+#if defined(OS_MACOSX)
+  // Public to be called by an ObjC bridge object.
+  void ActionPerformed(int control);
+  void URLEntered(std::string url_string);
+#endif
+
  private:
   enum UIControl {
     BACK_BUTTON,
@@ -69,7 +75,7 @@ class Shell : public TabContentsDelegate {
   // Called from the destructor to let each platform do any necessary cleanup.
   void PlatformCleanUp();
   // Creates the main window GUI.
-  void PlatformCreateWindow();
+  void PlatformCreateWindow(int width, int height);
   // Resizes the main window to the given dimensions.
   void PlatformSizeTo(int width, int height);
   // Resize the content area and GUI.
diff --git a/content/shell/shell_gtk.cc b/content/shell/shell_gtk.cc
index 12ac1d8..a08202f 100644
--- a/content/shell/shell_gtk.cc
+++ b/content/shell/shell_gtk.cc
@@ -29,7 +29,7 @@ void Shell::PlatformEnableUIControl(UIControl control, bool is_enabled) {
 void Shell::PlatformSetAddressBarURL(const GURL& url) {
 }
 
-void Shell::PlatformCreateWindow() {
+void Shell::PlatformCreateWindow(int width, int height) {
   NOTIMPLEMENTED();
 }
 
diff --git a/content/shell/shell_mac.mm b/content/shell/shell_mac.mm
index 12ac1d8..db9fc6d 100644
--- a/content/shell/shell_mac.mm
+++ b/content/shell/shell_mac.mm
@@ -5,40 +5,213 @@
 #include "content/shell/shell.h"
 
 #include "base/logging.h"
+#import "base/mac/cocoa_protocols.h"
 #include "base/string_piece.h"
+#include "base/sys_string_conversions.h"
+#include "content/shell/resource.h"
+
+// Receives notification that the window is closing so that it can start the
+// tear-down process. Is responsible for deleting itself when done.
+@interface ContentShellWindowDelegate : NSObject<NSWindowDelegate> {
+ @private
+  content::Shell* shell_;
+}
+- (id)initWithShell:(content::Shell*)shell;
+@end
+
+@implementation ContentShellWindowDelegate
+
+- (id)initWithShell:(content::Shell*)shell {
+  if ((self = [super init])) {
+    shell_ = shell;
+  }
+  return self;
+}
+
+// Called when the window is about to close. Perform the self-destruction
+// sequence by getting rid of the shell and removing it and the window from
+// the various global lists. Instead of doing it here, however, we fire off
+// a delayed call to |-cleanup:| to allow everything to get off the stack
+// before we go deleting objects. By returning YES, we allow the window to be
+// removed from the screen.
+- (BOOL)windowShouldClose:(id)window {
+  [window autorelease];
+
+  // Clean ourselves up and do the work after clearing the stack of anything
+  // that might have the shell on it.
+  [self performSelectorOnMainThread:@selector(cleanup:)
+                         withObject:window
+                      waitUntilDone:NO];
+
+  return YES;
+}
+
+// Does the work of removing the window from our various bookkeeping lists
+// and gets rid of the shell.
+- (void)cleanup:(id)window {
+  delete shell_;
+
+  [self release];
+}
+
+- (void)performAction:(id)sender {
+  shell_->ActionPerformed([sender tag]);
+}
+
+- (void)takeURLStringValueFrom:(id)sender {
+  shell_->URLEntered(base::SysNSStringToUTF8([sender stringValue]));
+}
+
+@end
+
+namespace {
+
+NSString* kWindowTitle = @"Content Shell";
+
+const int kButtonWidth = 72;
+const int kURLBarHeight = 24;
+
+void MakeShellButton(NSRect* rect,
+                     NSString* title,
+                     NSView* parent,
+                     int control,
+                     NSView* target) {
+  NSButton* button = [[[NSButton alloc] initWithFrame:*rect] autorelease];
+  [button setTitle:title];
+  [button setBezelStyle:NSSmallSquareBezelStyle];
+  [button setAutoresizingMask:(NSViewMaxXMargin | NSViewMinYMargin)];
+  [button setTarget:target];
+  [button setAction:@selector(performAction:)];
+  [button setTag:control];
+  [parent addSubview:button];
+  rect->origin.x += kButtonWidth;
+}
+
+}  // namespace
 
 namespace content {
 
 void Shell::PlatformInitialize() {
-  NOTIMPLEMENTED();
 }
 
 base::StringPiece Shell::PlatformResourceProvider(int key) {
-  NOTIMPLEMENTED();
   return base::StringPiece();
 }
 
 void Shell::PlatformCleanUp() {
-  NOTIMPLEMENTED();
 }
 
 void Shell::PlatformEnableUIControl(UIControl control, bool is_enabled) {
-  NOTIMPLEMENTED();
+  int id;
+  switch (control) {
+    case BACK_BUTTON:
+      id = IDC_NAV_BACK;
+      break;
+    case FORWARD_BUTTON:
+      id = IDC_NAV_FORWARD;
+      break;
+    case STOP_BUTTON:
+      id = IDC_NAV_STOP;
+      break;
+    default:
+      NOTREACHED() << "Unknown UI control";
+      return;
+  }
+  [[[window_ contentView] viewWithTag:id] setEnabled:is_enabled];
 }
 
 void Shell::PlatformSetAddressBarURL(const GURL& url) {
+  NSString* url_string = base::SysUTF8ToNSString(url.spec());
+  [url_edit_view_ setStringValue:url_string];
 }
 
-void Shell::PlatformCreateWindow() {
-  NOTIMPLEMENTED();
+void Shell::PlatformCreateWindow(int width, int height) {
+  NSRect initial_window_bounds = NSMakeRect(0, 0, width, height);
+  window_ = [[NSWindow alloc] initWithContentRect:initial_window_bounds
+                                        styleMask:(NSTitledWindowMask |
+                                                   NSClosableWindowMask |
+                                                   NSMiniaturizableWindowMask |
+                                                   NSResizableWindowMask )
+                                          backing:NSBackingStoreBuffered
+                                            defer:NO];
+  [window_ setTitle:kWindowTitle];
+
+  // Rely on the window delegate to clean us up rather than immediately
+  // releasing when the window gets closed. We use the delegate to do
+  // everything from the autorelease pool so the shell isn't on the stack
+  // during cleanup (ie, a window close from javascript).
+  [window_ setReleasedWhenClosed:NO];
+
+  // Create a window delegate to watch for when it's asked to go away. It will
+  // clean itself up so we don't need to hold a reference.
+  ContentShellWindowDelegate* delegate =
+      [[ContentShellWindowDelegate alloc] initWithShell:this];
+  [window_ setDelegate:delegate];
+
+  NSRect button_frame =
+      NSMakeRect(0, NSMaxY(initial_window_bounds) - kURLBarHeight,
+                 kButtonWidth, kURLBarHeight);
+
+  NSView* content = [window_ contentView];
+
+  MakeShellButton(&button_frame, @"Back", content, IDC_NAV_BACK,
+                  (NSView*)delegate);
+  MakeShellButton(&button_frame, @"Forward", content, IDC_NAV_FORWARD,
+                  (NSView*)delegate);
+  MakeShellButton(&button_frame, @"Reload", content, IDC_NAV_RELOAD,
+                  (NSView*)delegate);
+  MakeShellButton(&button_frame, @"Stop", content, IDC_NAV_STOP,
+                  (NSView*)delegate);
+
+  button_frame.size.width =
+      NSWidth(initial_window_bounds) - NSMinX(button_frame);
+  url_edit_view_ =
+      [[[NSTextField alloc] initWithFrame:button_frame] autorelease];
+  [content addSubview:url_edit_view_];
+  [url_edit_view_ setAutoresizingMask:(NSViewWidthSizable | NSViewMinYMargin)];
+  [url_edit_view_ setTarget:delegate];
+  [url_edit_view_ setAction:@selector(takeURLStringValueFrom:)];
+  [[url_edit_view_ cell] setWraps:NO];
+  [[url_edit_view_ cell] setScrollable:YES];
+
+  // show the window
+  [window_ makeKeyAndOrderFront:nil];
 }
 
 void Shell::PlatformSizeTo(int width, int height) {
-  NOTIMPLEMENTED();
+  NSRect frame = [window_ frame];
+  frame.size = NSMakeSize(width, height);
+  [window_ setFrame:frame display:YES];
 }
 
 void Shell::PlatformResizeSubViews() {
-  NOTIMPLEMENTED();
+  // Not needed; subviews are bound.
+}
+
+void Shell::ActionPerformed(int control) {
+  switch (control) {
+    case IDC_NAV_BACK:
+      GoBackOrForward(-1);
+      break;
+    case IDC_NAV_FORWARD:
+      GoBackOrForward(1);
+      break;
+    case IDC_NAV_RELOAD:
+      Reload();
+      break;
+    case IDC_NAV_STOP:
+      Stop();
+      break;
+  }
+}
+
+void Shell::URLEntered(std::string url_string) {
+  if (!url_string.empty()) {
+    GURL url(url_string);
+    if (!url.has_scheme())
+      url = GURL("http://" + url_string);
+    LoadURL(url);
+  }
 }
 
 }  // namespace content
diff --git a/content/shell/shell_win.cc b/content/shell/shell_win.cc
index a499189..7a0a1b9 100644
--- a/content/shell/shell_win.cc
+++ b/content/shell/shell_win.cc
@@ -22,13 +22,13 @@
 
 namespace {
 
-static const wchar_t kWindowTitle[] = L"Content Shell";
-static const wchar_t kWindowClass[] = L"CONTENT_SHELL";
+const wchar_t kWindowTitle[] = L"Content Shell";
+const wchar_t kWindowClass[] = L"CONTENT_SHELL";
 
-static const int kButtonWidth = 72;
-static const int kURLBarHeight = 24;
+const int kButtonWidth = 72;
+const int kURLBarHeight = 24;
 
-static const int kMaxURLLength = 1024;
+const int kMaxURLLength = 1024;
 
 static base::StringPiece GetRawDataResource(HMODULE module, int resource_id) {
   void* data_ptr;
@@ -94,7 +94,7 @@ void Shell::PlatformSetAddressBarURL(const GURL& url) {
               reinterpret_cast<LPARAM>(url_string.c_str()));
 }
 
-void Shell::PlatformCreateWindow() {
+void Shell::PlatformCreateWindow(int width, int height) {
   window_ = CreateWindow(kWindowClass, kWindowTitle,
                          WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
                          CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
@@ -139,6 +139,8 @@ void Shell::PlatformCreateWindow() {
   ui::SetWindowUserData(url_edit_view_, this);
 
   ShowWindow(window_, SW_SHOW);
+
+  PlatformSizeTo(width, height);
 }
 
 void Shell::PlatformSizeTo(int width, int height) {
@@ -216,15 +218,11 @@ LRESULT CALLBACK Shell::WndProc(HWND hwnd, UINT message, WPARAM wParam,
           shell->GoBackOrForward(1);
           break;
         case IDC_NAV_RELOAD:
-        case IDC_NAV_STOP: {
-          if (id == IDC_NAV_RELOAD) {
-            shell->Reload();
-          } else {
-            shell->Stop();
-          }
+          shell->Reload();
+          break;
+        case IDC_NAV_STOP:
+          shell->Stop();
           break;
-        }
-        break;
       }
       break;
     }
-- 
cgit v1.1