summaryrefslogtreecommitdiffstats
path: root/content/shell/shell_mac.mm
blob: db9fc6de0af20d7c691fd1c706e0056067e406f0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#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() {
}

base::StringPiece Shell::PlatformResourceProvider(int key) {
  return base::StringPiece();
}

void Shell::PlatformCleanUp() {
}

void Shell::PlatformEnableUIControl(UIControl control, bool is_enabled) {
  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(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) {
  NSRect frame = [window_ frame];
  frame.size = NSMakeSize(width, height);
  [window_ setFrame:frame display:YES];
}

void Shell::PlatformResizeSubViews() {
  // 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