Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(215)

Side by Side Diff: remoting/ios/ui/host_view_controller.mm

Issue 475333004: Remove old Chromoting iOS client (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « remoting/ios/ui/host_view_controller.h ('k') | remoting/ios/ui/pin_entry_view_controller.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #if !defined(__has_feature) || !__has_feature(objc_arc)
6 #error "This file requires ARC support."
7 #endif
8
9 #import "remoting/ios/ui/host_view_controller.h"
10
11 #include <OpenGLES/ES2/gl.h>
12
13 #import "remoting/ios/data_store.h"
14
15 namespace {
16
17 // TODO (aboone) Some of the layout is not yet set in stone, so variables have
18 // been used to position and turn items on and off. Eventually these may be
19 // stabilized and removed.
20
21 // Scroll speed multiplier for mouse wheel
22 const static int kMouseWheelSensitivity = 20;
23
24 // Area the navigation bar consumes when visible in pixels
25 const static int kTopMargin = 20;
26 // Area the footer consumes when visible (no footer currently exists)
27 const static int kBottomMargin = 0;
28
29 } // namespace
30
31 @interface HostViewController (Private)
32 - (void)setupGL;
33 - (void)tearDownGL;
34 - (void)goBack;
35 - (void)updateLabels;
36 - (BOOL)isToolbarHidden;
37 - (void)updatePanVelocityShouldCancel:(bool)canceled;
38 - (void)orientationChanged:(NSNotification*)note;
39 - (void)applySceneChange:(CGPoint)translation scaleBy:(float)ratio;
40 - (void)showToolbar:(BOOL)visible;
41 @end
42
43 @implementation HostViewController
44
45 @synthesize host = _host;
46 @synthesize userEmail = _userEmail;
47 @synthesize userAuthorizationToken = _userAuthorizationToken;
48
49 // Override UIViewController
50 - (void)viewDidLoad {
51 [super viewDidLoad];
52
53 _context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
54 DCHECK(_context);
55 static_cast<GLKView*>(self.view).context = _context;
56
57 [_keyEntryView setDelegate:self];
58
59 _clientToHostProxy = [[HostProxy alloc] init];
60
61 // There is a 1 pixel top border which is actually the background not being
62 // covered. There is no obvious way to remove that pixel 'border'. Set the
63 // background clear, and also reset the backgroundimage and shawdowimage to an
64 // empty image any time the view is moved.
65 _hiddenToolbar.backgroundColor = [UIColor clearColor];
66 if ([_hiddenToolbar respondsToSelector:@selector(setBackgroundImage:
67 forToolbarPosition:
68 barMetrics:)]) {
69 [_hiddenToolbar setBackgroundImage:[UIImage new]
70 forToolbarPosition:UIToolbarPositionAny
71 barMetrics:UIBarMetricsDefault];
72 }
73 if ([_hiddenToolbar
74 respondsToSelector:@selector(setShadowImage:forToolbarPosition:)]) {
75 [_hiddenToolbar setShadowImage:[UIImage new]
76 forToolbarPosition:UIToolbarPositionAny];
77 }
78
79 // 1/2 circle rotation for an icon ~ 180 degree ~ 1 radian
80 _barBtnNavigation.imageView.transform = CGAffineTransformMakeRotation(M_PI);
81
82 _scene = [[SceneView alloc] init];
83 [_scene setMarginsFromLeft:0 right:0 top:kTopMargin bottom:kBottomMargin];
84 _desktop = [[DesktopTexture alloc] init];
85 _mouse = [[CursorTexture alloc] init];
86
87 _glBufferLock = [[NSLock alloc] init];
88 _glCursorLock = [[NSLock alloc] init];
89
90 [_scene
91 setContentSize:[Utility getOrientatedSize:self.view.bounds.size
92 shouldWidthBeLongestSide:[Utility isInLandscapeMode]]];
93 [self showToolbar:YES];
94 [self updateLabels];
95
96 [self setupGL];
97
98 [_singleTapRecognizer requireGestureRecognizerToFail:_twoFingerTapRecognizer];
99 [_twoFingerTapRecognizer
100 requireGestureRecognizerToFail:_threeFingerTapRecognizer];
101 //[_pinchRecognizer requireGestureRecognizerToFail:_twoFingerTapRecognizer];
102 [_panRecognizer requireGestureRecognizerToFail:_singleTapRecognizer];
103 [_threeFingerPanRecognizer
104 requireGestureRecognizerToFail:_threeFingerTapRecognizer];
105 //[_pinchRecognizer requireGestureRecognizerToFail:_threeFingerPanRecognizer];
106
107 // Subscribe to changes in orientation
108 [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
109 [[NSNotificationCenter defaultCenter]
110 addObserver:self
111 selector:@selector(orientationChanged:)
112 name:UIDeviceOrientationDidChangeNotification
113 object:[UIDevice currentDevice]];
114 }
115
116 - (void)setupGL {
117 [EAGLContext setCurrentContext:_context];
118
119 _effect = [[GLKBaseEffect alloc] init];
120 [Utility logGLErrorCode:@"setupGL begin"];
121
122 // Initialize each texture
123 [_desktop bindToEffect:[_effect texture2d0]];
124 [_mouse bindToEffect:[_effect texture2d1]];
125 [Utility logGLErrorCode:@"setupGL textureComplete"];
126 }
127
128 // Override UIViewController
129 - (void)viewDidUnload {
130 [super viewDidUnload];
131 [self tearDownGL];
132
133 if ([EAGLContext currentContext] == _context) {
134 [EAGLContext setCurrentContext:nil];
135 }
136 _context = nil;
137 }
138
139 - (void)tearDownGL {
140 [EAGLContext setCurrentContext:_context];
141
142 // Release Textures
143 [_desktop releaseTexture];
144 [_mouse releaseTexture];
145 }
146
147 // Override UIViewController
148 - (void)viewWillAppear:(BOOL)animated {
149 [super viewWillAppear:NO];
150 [self.navigationController setNavigationBarHidden:YES animated:YES];
151 [self updateLabels];
152 if (![_clientToHostProxy isConnected]) {
153 [_busyIndicator startAnimating];
154
155 [_clientToHostProxy connectToHost:_userEmail
156 authToken:_userAuthorizationToken
157 jabberId:_host.jabberId
158 hostId:_host.hostId
159 publicKey:_host.publicKey
160 delegate:self];
161 }
162 }
163
164 // Override UIViewController
165 - (void)viewWillDisappear:(BOOL)animated {
166 [super viewWillDisappear:NO];
167 NSArray* viewControllers = self.navigationController.viewControllers;
168 if (viewControllers.count > 1 &&
169 [viewControllers objectAtIndex:viewControllers.count - 2] == self) {
170 // View is disappearing because a new view controller was pushed onto the
171 // stack
172 } else if ([viewControllers indexOfObject:self] == NSNotFound) {
173 // View is disappearing because it was popped from the stack
174 [_clientToHostProxy disconnectFromHost];
175 }
176 }
177
178 // "Back" goes to the root controller for now
179 - (void)goBack {
180 [self.navigationController popToRootViewControllerAnimated:YES];
181 }
182
183 // @protocol PinEntryViewControllerDelegate
184 // Return the PIN input by User, indicate if the User should be prompted to
185 // re-enter the pin in the future
186 - (void)connectToHostWithPin:(UIViewController*)controller
187 hostPin:(NSString*)hostPin
188 shouldPrompt:(BOOL)shouldPrompt {
189 const HostPreferences* hostPrefs =
190 [[DataStore sharedStore] getHostForId:_host.hostId];
191 if (!hostPrefs) {
192 hostPrefs = [[DataStore sharedStore] createHost:_host.hostId];
193 }
194 if (hostPrefs) {
195 hostPrefs.hostPin = hostPin;
196 hostPrefs.askForPin = [NSNumber numberWithBool:shouldPrompt];
197 [[DataStore sharedStore] saveChanges];
198 }
199
200 [[controller presentingViewController] dismissViewControllerAnimated:NO
201 completion:nil];
202
203 [_clientToHostProxy authenticationResponse:hostPin createPair:!shouldPrompt];
204 }
205
206 // @protocol PinEntryViewControllerDelegate
207 // Returns if the user canceled while entering their PIN
208 - (void)cancelledConnectToHostWithPin:(UIViewController*)controller {
209 [[controller presentingViewController] dismissViewControllerAnimated:NO
210 completion:nil];
211
212 [self goBack];
213 }
214
215 - (void)setHostDetails:(Host*)host
216 userEmail:(NSString*)userEmail
217 authorizationToken:(NSString*)authorizationToken {
218 DCHECK(host.jabberId);
219 _host = host;
220 _userEmail = userEmail;
221 _userAuthorizationToken = authorizationToken;
222 }
223
224 // Set various labels on the form for iPad vs iPhone, and orientation
225 - (void)updateLabels {
226 if (![Utility isPad] && ![Utility isInLandscapeMode]) {
227 [_barBtnDisconnect setTitle:@"" forState:(UIControlStateNormal)];
228 [_barBtnCtrlAltDel setTitle:@"CtAtD" forState:UIControlStateNormal];
229 } else {
230 [_barBtnCtrlAltDel setTitle:@"Ctrl+Alt+Del" forState:UIControlStateNormal];
231
232 NSString* hostStatus = _host.hostName;
233 if (![_statusMessage isEqual:@"Connected"]) {
234 hostStatus = [NSString
235 stringWithFormat:@"%@ - %@", _host.hostName, _statusMessage];
236 }
237 [_barBtnDisconnect setTitle:hostStatus forState:UIControlStateNormal];
238 }
239
240 [_barBtnDisconnect sizeToFit];
241 [_barBtnCtrlAltDel sizeToFit];
242 }
243
244 // Resize the view of the desktop - Zoom in/out. This can occur during a Pan.
245 - (IBAction)pinchGestureTriggered:(UIPinchGestureRecognizer*)sender {
246 if ([sender state] == UIGestureRecognizerStateChanged) {
247 [self applySceneChange:CGPointMake(0.0, 0.0) scaleBy:sender.scale];
248
249 sender.scale = 1.0; // reset scale so next iteration is a relative ratio
250 }
251 }
252
253 - (IBAction)tapGestureTriggered:(UITapGestureRecognizer*)sender {
254 if ([_scene containsTouchPoint:[sender locationInView:self.view]]) {
255 [Utility leftClickOn:_clientToHostProxy at:_scene.mousePosition];
256 }
257 }
258
259 // Change position of scene. This can occur during a pinch or longpress.
260 // Or perform a Mouse Wheel Scroll
261 - (IBAction)panGestureTriggered:(UIPanGestureRecognizer*)sender {
262 CGPoint translation = [sender translationInView:self.view];
263
264 // If we start with 2 touches, and the pinch gesture is not in progress yet,
265 // then disable it, so mouse scrolling and zoom do not occur at the same
266 // time.
267 if ([sender numberOfTouches] == 2 &&
268 [sender state] == UIGestureRecognizerStateBegan &&
269 !(_pinchRecognizer.state == UIGestureRecognizerStateBegan ||
270 _pinchRecognizer.state == UIGestureRecognizerStateChanged)) {
271 _pinchRecognizer.enabled = NO;
272 }
273
274 if (!_pinchRecognizer.enabled) {
275 // Began with 2 touches, so this is a scroll event
276 translation.x *= kMouseWheelSensitivity;
277 translation.y *= kMouseWheelSensitivity;
278 [Utility mouseScroll:_clientToHostProxy
279 at:_scene.mousePosition
280 delta:webrtc::DesktopVector(translation.x, translation.y)];
281 } else {
282 // Did not begin with 2 touches, doing a pan event
283 if ([sender state] == UIGestureRecognizerStateChanged) {
284 CGPoint translation = [sender translationInView:self.view];
285
286 [self applySceneChange:translation scaleBy:1.0];
287
288 } else if ([sender state] == UIGestureRecognizerStateEnded) {
289 // After user removes their fingers from the screen, apply an acceleration
290 // effect
291 [_scene setPanVelocity:[sender velocityInView:self.view]];
292 }
293 }
294
295 // Finished the event chain
296 if (!([sender state] == UIGestureRecognizerStateBegan ||
297 [sender state] == UIGestureRecognizerStateChanged)) {
298 _pinchRecognizer.enabled = YES;
299 }
300
301 // Reset translation so next iteration is relative.
302 [sender setTranslation:CGPointZero inView:self.view];
303 }
304
305 // Click-Drag mouse operation. This can occur during a Pan.
306 - (IBAction)longPressGestureTriggered:(UILongPressGestureRecognizer*)sender {
307
308 if ([sender state] == UIGestureRecognizerStateBegan) {
309 [_clientToHostProxy mouseAction:_scene.mousePosition
310 wheelDelta:webrtc::DesktopVector(0, 0)
311 whichButton:1
312 buttonDown:YES];
313 } else if (!([sender state] == UIGestureRecognizerStateBegan ||
314 [sender state] == UIGestureRecognizerStateChanged)) {
315 [_clientToHostProxy mouseAction:_scene.mousePosition
316 wheelDelta:webrtc::DesktopVector(0, 0)
317 whichButton:1
318 buttonDown:NO];
319 }
320 }
321
322 - (IBAction)twoFingerTapGestureTriggered:(UITapGestureRecognizer*)sender {
323 if ([_scene containsTouchPoint:[sender locationInView:self.view]]) {
324 [Utility rightClickOn:_clientToHostProxy at:_scene.mousePosition];
325 }
326 }
327
328 - (IBAction)threeFingerTapGestureTriggered:(UITapGestureRecognizer*)sender {
329
330 if ([_scene containsTouchPoint:[sender locationInView:self.view]]) {
331 [Utility middleClickOn:_clientToHostProxy at:_scene.mousePosition];
332 }
333 }
334
335 - (IBAction)threeFingerPanGestureTriggered:(UIPanGestureRecognizer*)sender {
336 if ([sender state] == UIGestureRecognizerStateChanged) {
337 CGPoint translation = [sender translationInView:self.view];
338 if (translation.y > 0) {
339 // Swiped down
340 [self showToolbar:YES];
341 } else if (translation.y < 0) {
342 // Swiped up
343 [_keyEntryView becomeFirstResponder];
344 [self updateLabels];
345 }
346 [sender setTranslation:CGPointZero inView:self.view];
347 }
348 }
349
350 - (IBAction)barBtnNavigationBackPressed:(id)sender {
351 [self goBack];
352 }
353
354 - (IBAction)barBtnKeyboardPressed:(id)sender {
355 if ([_keyEntryView isFirstResponder]) {
356 [_keyEntryView endEditing:NO];
357 } else {
358 [_keyEntryView becomeFirstResponder];
359 }
360
361 [self updateLabels];
362 }
363
364 - (IBAction)barBtnToolBarHidePressed:(id)sender {
365 [self showToolbar:[self isToolbarHidden]]; // Toolbar is either on
366 // screen or off screen
367 }
368
369 - (IBAction)barBtnCtrlAltDelPressed:(id)sender {
370 [_keyEntryView ctrlAltDel];
371 }
372
373 // Override UIResponder
374 // When any gesture begins, remove any acceleration effects currently being
375 // applied. Example, Panning view and let it shoot off into the distance, but
376 // then I see a spot I'm interested in so I will touch to capture that locations
377 // focus.
378 - (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
379 [self updatePanVelocityShouldCancel:YES];
380 [super touchesBegan:touches withEvent:event];
381 }
382
383 // @protocol UIGestureRecognizerDelegate
384 // Allow panning and zooming to occur simultaneously.
385 // Allow panning and long press to occur simultaneously.
386 // Pinch requires 2 touches, and long press requires a single touch, so they are
387 // mutually exclusive regardless of if panning is the initiating gesture
388 - (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer
389 shouldRecognizeSimultaneouslyWithGestureRecognizer:
390 (UIGestureRecognizer*)otherGestureRecognizer {
391 if (gestureRecognizer == _pinchRecognizer ||
392 (gestureRecognizer == _panRecognizer)) {
393 if (otherGestureRecognizer == _pinchRecognizer ||
394 otherGestureRecognizer == _panRecognizer) {
395 return YES;
396 }
397 }
398
399 if (gestureRecognizer == _longPressRecognizer ||
400 gestureRecognizer == _panRecognizer) {
401 if (otherGestureRecognizer == _longPressRecognizer ||
402 otherGestureRecognizer == _panRecognizer) {
403 return YES;
404 }
405 }
406 return NO;
407 }
408
409 // @protocol ClientControllerDelegate
410 // Prompt the user for their PIN if pairing has not already been established
411 - (void)requestHostPin:(BOOL)pairingSupported {
412 BOOL requestPin = YES;
413 const HostPreferences* hostPrefs =
414 [[DataStore sharedStore] getHostForId:_host.hostId];
415 if (hostPrefs) {
416 requestPin = [hostPrefs.askForPin boolValue];
417 if (!requestPin) {
418 if (hostPrefs.hostPin == nil || hostPrefs.hostPin.length == 0) {
419 requestPin = YES;
420 }
421 }
422 }
423 if (requestPin == YES) {
424 PinEntryViewController* pinEntry = [[PinEntryViewController alloc] init];
425 [pinEntry setDelegate:self];
426 [pinEntry setHostName:_host.hostName];
427 [pinEntry setShouldPrompt:YES];
428 [pinEntry setPairingSupported:pairingSupported];
429
430 [self presentViewController:pinEntry animated:YES completion:nil];
431 } else {
432 [_clientToHostProxy authenticationResponse:hostPrefs.hostPin
433 createPair:pairingSupported];
434 }
435 }
436
437 // @protocol ClientControllerDelegate
438 // Occurs when a connection to a HOST is established successfully
439 - (void)connected {
440 // Everything is good, nothing to do
441 }
442
443 // @protocol ClientControllerDelegate
444 - (void)connectionStatus:(NSString*)statusMessage {
445 _statusMessage = statusMessage;
446
447 if ([_statusMessage isEqual:@"Connection closed"]) {
448 [self goBack];
449 } else {
450 [self updateLabels];
451 }
452 }
453
454 // @protocol ClientControllerDelegate
455 // Occurs when a connection to a HOST has failed
456 - (void)connectionFailed:(NSString*)errorMessage {
457 [_busyIndicator stopAnimating];
458 NSString* errorMsg;
459 if ([_clientToHostProxy isConnected]) {
460 errorMsg = @"Lost Connection";
461 } else {
462 errorMsg = @"Unable to connect";
463 }
464 [Utility showAlert:errorMsg message:errorMessage];
465 [self goBack];
466 }
467
468 // @protocol ClientControllerDelegate
469 // Copy the updated regions to a backing store to be consumed by the GL Context
470 // on a different thread. A region is stored in disjoint memory locations, and
471 // must be transformed to a contiguous memory buffer for a GL Texture write.
472 // /-----\
473 // | 2-4| This buffer is 5x3 bytes large, a region exists at bytes 2 to 4 and
474 // | 7-9| bytes 7 to 9. The region is extracted to a new contiguous buffer
475 // | | of 6 bytes in length.
476 // \-----/
477 // More than 1 region may exist in the frame from each call, in which case a new
478 // buffer is created for each region
479 - (void)applyFrame:(const webrtc::DesktopSize&)size
480 stride:(NSInteger)stride
481 data:(uint8_t*)data
482 regions:(const std::vector<webrtc::DesktopRect>&)regions {
483 [_glBufferLock lock]; // going to make changes to |_glRegions|
484
485 if (!_scene.frameSize.equals(size)) {
486 // When this is the initial frame, the busyIndicator is still spinning. Now
487 // is a good time to stop it.
488 [_busyIndicator stopAnimating];
489
490 // If the |_toolbar| is still showing, hide it.
491 [self showToolbar:NO];
492 [_scene setContentSize:
493 [Utility getOrientatedSize:self.view.bounds.size
494 shouldWidthBeLongestSide:[Utility isInLandscapeMode]]];
495 [_scene setFrameSize:size];
496 [_desktop setTextureSize:size];
497 [_mouse setTextureSize:size];
498 }
499
500 uint32_t src_stride = stride;
501
502 for (uint32_t i = 0; i < regions.size(); i++) {
503 scoped_ptr<GLRegion> region(new GLRegion());
504
505 if (region.get()) {
506 webrtc::DesktopRect rect = regions.at(i);
507
508 webrtc::DesktopSize(rect.width(), rect.height());
509 region->offset.reset(new webrtc::DesktopVector(rect.left(), rect.top()));
510 region->image.reset(new webrtc::BasicDesktopFrame(
511 webrtc::DesktopSize(rect.width(), rect.height())));
512
513 if (region->image->data()) {
514 uint32_t bytes_per_row =
515 region->image->kBytesPerPixel * region->image->size().width();
516
517 uint32_t offset =
518 (src_stride * region->offset->y()) + // row
519 (region->offset->x() * region->image->kBytesPerPixel); // column
520
521 uint8_t* src_buffer = data + offset;
522 uint8_t* dst_buffer = region->image->data();
523
524 // row by row copy
525 for (uint32_t j = 0; j < region->image->size().height(); j++) {
526 memcpy(dst_buffer, src_buffer, bytes_per_row);
527 dst_buffer += bytes_per_row;
528 src_buffer += src_stride;
529 }
530 _glRegions.push_back(region.release());
531 }
532 }
533 }
534 [_glBufferLock unlock]; // done making changes to |_glRegions|
535 }
536
537 // @protocol ClientControllerDelegate
538 // Copy the delivered cursor to a backing store to be consumed by the GL Context
539 // on a different thread. Note only the most recent cursor is of importance,
540 // discard the previous cursor.
541 - (void)applyCursor:(const webrtc::DesktopSize&)size
542 hotspot:(const webrtc::DesktopVector&)hotspot
543 cursorData:(uint8_t*)data {
544
545 [_glCursorLock lock]; // going to make changes to |_cursor|
546
547 // MouseCursor takes ownership of DesktopFrame
548 [_mouse setCursor:new webrtc::MouseCursor(new webrtc::BasicDesktopFrame(size),
549 hotspot)];
550
551 if (_mouse.cursor.image().data()) {
552 memcpy(_mouse.cursor.image().data(),
553 data,
554 size.width() * size.height() * _mouse.cursor.image().kBytesPerPixel);
555 } else {
556 [_mouse setCursor:NULL];
557 }
558
559 [_glCursorLock unlock]; // done making changes to |_cursor|
560 }
561
562 // @protocol GLKViewDelegate
563 // There is quite a few gotchas involved in working with this function. For
564 // sanity purposes, I've just assumed calls to the function are on a different
565 // thread which I've termed GL Context. Any variables consumed by this function
566 // should be thread safe.
567 //
568 // Clear Screen, update desktop, update cursor, define position, and finally
569 // present
570 //
571 // In general, avoid expensive work in this function to maximize frame rate.
572 - (void)glkView:(GLKView*)view drawInRect:(CGRect)rect {
573 [self updatePanVelocityShouldCancel:NO];
574
575 // Clear to black, to give the background color
576 glClearColor(0.0, 0.0, 0.0, 1.0);
577 glClear(GL_COLOR_BUFFER_BIT);
578
579 [Utility logGLErrorCode:@"drawInRect bindBuffer"];
580
581 if (_glRegions.size() > 0 || [_desktop needDraw]) {
582 [_glBufferLock lock];
583
584 for (uint32_t i = 0; i < _glRegions.size(); i++) {
585 // |_glRegions[i].data| has been properly ordered by [self applyFrame]
586 [_desktop drawRegion:_glRegions[i] rect:rect];
587 }
588
589 _glRegions.clear();
590 [_glBufferLock unlock];
591 }
592
593 if ([_mouse needDrawAtPosition:_scene.mousePosition]) {
594 [_glCursorLock lock];
595 [_mouse drawWithMousePosition:_scene.mousePosition];
596 [_glCursorLock unlock];
597 }
598
599 [_effect transform].projectionMatrix = _scene.projectionMatrix;
600 [_effect transform].modelviewMatrix = _scene.modelViewMatrix;
601 [_effect prepareToDraw];
602
603 [Utility logGLErrorCode:@"drawInRect prepareToDrawComplete"];
604
605 [_scene draw];
606 }
607
608 // @protocol KeyInputDelegate
609 - (void)keyboardDismissed {
610 [self updateLabels];
611 }
612
613 // @protocol KeyInputDelegate
614 // Send keyboard input to HOST
615 - (void)keyboardActionKeyCode:(uint32_t)keyPressed isKeyDown:(BOOL)keyDown {
616 [_clientToHostProxy keyboardAction:keyPressed keyDown:keyDown];
617 }
618
619 - (BOOL)isToolbarHidden {
620 return (_toolbar.frame.origin.y < 0);
621 }
622
623 // Update the scene acceleration vector
624 - (void)updatePanVelocityShouldCancel:(bool)canceled {
625 if (canceled) {
626 [_scene setPanVelocity:CGPointMake(0, 0)];
627 }
628 BOOL inMotion = [_scene tickPanVelocity];
629
630 _singleTapRecognizer.enabled = !inMotion;
631 _longPressRecognizer.enabled = !inMotion;
632 }
633
634 - (void)applySceneChange:(CGPoint)translation scaleBy:(float)ratio {
635 [_scene panAndZoom:translation scaleBy:ratio];
636 // Notify HOST that the mouse moved
637 [Utility moveMouse:_clientToHostProxy at:_scene.mousePosition];
638 }
639
640 // Callback from NSNotificationCenter when the User changes orientation
641 - (void)orientationChanged:(NSNotification*)note {
642 [_scene
643 setContentSize:[Utility getOrientatedSize:self.view.bounds.size
644 shouldWidthBeLongestSide:[Utility isInLandscapeMode]]];
645 [self showToolbar:![self isToolbarHidden]];
646 [self updateLabels];
647 }
648
649 // Animate |_toolbar| by moving it on or offscreen
650 - (void)showToolbar:(BOOL)visible {
651 CGRect frame = [_toolbar frame];
652
653 _toolBarYPosition.constant = -frame.size.height;
654 int topOffset = kTopMargin;
655
656 if (visible) {
657 topOffset += frame.size.height;
658 _toolBarYPosition.constant = kTopMargin;
659 }
660
661 _hiddenToolbarYPosition.constant = topOffset;
662 [_scene setMarginsFromLeft:0 right:0 top:topOffset bottom:kBottomMargin];
663
664 // hidden when |_toolbar| is |visible|
665 _hiddenToolbar.hidden = (visible == YES);
666
667 [UIView animateWithDuration:0.5
668 animations:^{ [self.view layoutIfNeeded]; }
669 completion:^(BOOL finished) {// Nothing to do for now
670 }];
671
672 // Center view if needed for any reason.
673 // Specificallly, if the top anchor is active.
674 [self applySceneChange:CGPointMake(0.0, 0.0) scaleBy:1.0];
675 }
676 @end
OLDNEW
« no previous file with comments | « remoting/ios/ui/host_view_controller.h ('k') | remoting/ios/ui/pin_entry_view_controller.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698