Commit graph

20 commits

Author SHA1 Message Date
Michael Kitzan 3ac32af848 Converts Dispatcher().RunAsync to WinRT Coroutines (#4051)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? -->
## Summary of the Pull Request
This PR turns all* instances of `Dispatcher().RunAsync` to WinRT coroutines 👌. 
This was good coding fodder to fill my plane ride ✈️. Enjoy your holidays everyone!

*With the exception of three functions whose signatures cannot be changed due to inheritance and function overriding in `TermControlAutomationPeer` [`L44`](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp#L44), [`L58`](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp#L58),  [`L72`](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp#L72). 

<!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> 
## References

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
* [x] Closes #3919
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] Tests added/passed
* [ ] Requires documentation to be updated
* [x] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #3919

<!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments
My thought pattern here was to minimally disturb the existing code where possible. So where I could, I converted existing functions into coroutine using functions (like in the [core example](https://github.com/microsoft/terminal/issues/3919#issue-536598706)). For ~the most part~ all instances, I used the format where [`this` is accessed safely within a locked scope](https://github.com/microsoft/terminal/issues/3919#issuecomment-564730620). Some function signatures were changed to take objects by value instead of reference, so the coroutines don't crash when the objects are accessed past their original lifetime. The [copy](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalApp/TerminalPage.cpp#L1132) and [paste](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalApp/TerminalPage.cpp#L1170) event handler entry points were originally set to a high priority; however, the WinRT coroutines don't appear to support a priority scheme so this priority setting was not preserved in the translation.

<!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
Compiles and runs, and for every event with a clear trigger repro, I triggered it to ensure crashes weren't introduced.
2020-01-10 03:29:49 +00:00
mcpiroman d4c527607a Snap to character grid when resizing window (#3181)
When user resizes window, snap the size to align with the character grid
(like e.g. putty, mintty and most unix terminals). Properly resolves
arbitrary pane configuration (even with different font sizes and
padding) trying to align each pane as close as possible.

It also fixes terminal minimum size enforcement which was not quite well
handled, especially with multiple panes.

This PR does not however try to keep the terminals aligned at other user
actions (e.g. font change or pane split). That is to be tracked by some
other activity.

Snapping is resolved in the pane tree, recursively, so it (hopefully)
works for any possible layout.

Along the way I had to clean up some things as so to make the resulting
code not so cumbersome:
1. Pane.cpp: Replaced _firstPercent and _secondPercent with single
   _desiredSplitPosition to reduce invariants - these had to be kept in
   sync so their sum always gives 1 (and were not really a percent). The
   desired part refers to fact that since panes are aligned, there is
   usually some deviation from that ratio.
2. Pane.cpp: Fixed _GetMinSize() - it was improperly accounting for
   split direction
3. TerminalControl: Made dedicated member for padding instead of
   reading it from a control itself. This is because the winrt property
   functions turned out to be slow and this algorithm needs to access it
   many times. I also cached scrollbar width for the same reason.
4. AppHost: Moved window to client size resolution to virtual method,
   where IslandWindow and NonClientIslandWindow have their own
   implementations (as opposite to pointer casting).

One problem with current implementation is I had to make a long call
chain from the window that requests snapping to the (root) pane that
implements it: IslandWindow -> AppHost's callback -> App ->
TerminalPage -> Tab -> Pane. I don't know if this can be done better.

## Validation Steps Performed
Spam split pane buttons, randomly change font sizes with ctrl+mouse
wheel and drag the window back and forth.

Closes #2834
Closes #2277
2020-01-08 13:19:23 -08:00
Michael Kitzan 7b9728b4a9 Fixed self reference capture in Tab and TerminalPage (#3835)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? -->
## Summary of the Pull Request
Every lambda capture in `Tab` and `TerminalPage` has been changed from capturing raw `this` to `std::weak_ptr<Tab>` or `winrt::weak_ref<TerminalPage>`. Lambda bodies have been changed to check the weak reference before use. 

Capturing raw `this` in `Tab`'s [title change event handler](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalApp/Tab.cpp#L299) was the root cause of #3776, and is fixed in this PR among other instance of raw `this` capture.

The lambda fixes to `TerminalPage` are unrelated to the core issue addressed in the PR checklist. Because I was already editing `TerminalPage`, figured I'd do a [weak_ref pass](https://github.com/microsoft/terminal/issues/3776#issuecomment-560575575).

<!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> 
## References

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
* [x] Closes #3776, potentially #2248, likely closes others
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] Tests added/passed
* [ ] Requires documentation to be updated
* [x] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #3776

<!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments
`Tab` now inherits from `enable_shared_from_this`, which enable accessing `Tab` objects as `std::weak_ptr<Tab>` objects. All instances of lambdas capturing `this` now capture `std::weak_ptr<Tab>` instead. `TerminalPage` is a WinRT type which supports `winrt::weak_ref<TerminalPage>`. All previous instance of `TerminalPage` lambdas capturing `this` has been replaced to capture `winrt::weak_ref<TerminalPage>`. These weak pointers/references can only be created after object construction necessitating for `Tab` a new function called after construction to bind lambdas.

Any anomalous crash related to the following functionality during closing a tab or WT may be fixed by this PR:
- Tab icon updating
- Tab text updating
- Tab dragging
- Clicking new tab button
- Changing active pane
- Closing an active tab
- Clicking on a tab
- Creating the new tab flyout menu

Sorry about all the commits. Will fix my fork after this PR! 😅 

<!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
Attempted to repro the steps indicated in issue #3776 with the new changes and failed. When before the changes, the issue could consistently be reproed.
2019-12-05 23:18:22 +00:00
Mike Griese eed351eb47
Add a 'splitPane' ShortcutAction (#3722)
## Summary of the Pull Request

We already have "splitHorizontal" and "splitVertical", but those will both be deprecated in favor of "splitPane" with arguments. 

Currently, there's one argument: "style", which is one of "vertical" or "horizontal."

## References
This is being done in pursuit of supporting #607 and #998. I don't really want to lob #998 in with this one, since both that and this are hefty enough PRs even as they are. (I have a branch for #998, but it needs this first)

This will probably conflict with #3658
## PR Checklist
* [ ] Doesn't actually close anything, only enables #998
* [x] I work here
* [ ] Tests added/passed - yea okay no excuses here
* [x] Requires documentation to be updated

## Validation Steps Performed
Added new keybindings with the args - works
Tried the old keybindings without the args - still works
---------------------------------------
* Add a 'splitPane' keybinding that can be used for splitting a pane either vertically or horizontally

* Update documentation too

* Good lord this is important

* Add a test too, though I have no idea if it works

* "style" -> "split"

* pr comments from carlos
2019-11-28 07:42:15 -06:00
Dustin L. Howett (MSFT) 901a1e1a09
Implement ConnectionState and closeOnExit=graceful/always/never (#3623)
This pull request implements the new
`ITerminalConnection::ConnectionState` interface (enum, event) and
connects it through TerminalControl to Pane, Tab and App as specified in
#2039. It does so to implement `closeOnExit` = `graceful` in addition to
the other two normal CoE types.

It also:

* exposes the singleton `CascadiaSettings` through a function that
  looks it up by using the current Xaml application's `AppLogic`.
  * In so doing, we've broken up the weird runaround where App tells
    TerminalSettings to CloseOnExit and then later another part of App
    _asks TerminalControl_ to tell it what TerminalSettings said App
    told it earlier. `:crazy_eyes:`
* wires up a bunch of connection state points to `AzureConnection`.
  This required moving the Azure connection's state machine to use another
  enum name (oops).
* ships a helper class for managing connection state transitions.
* contains a bunch of template magic.
* introduces `WINRT_CALLBACK`, a oneshot callback like `TYPED_EVENT`.
* replaces a bunch of disparate `_connecting` and `_closing` members
  with just one uberstate.
* updates the JSON schema and defaults to prefer closeOnExit: graceful
* updates all relevant documentation

Specified in #2039
Fixes #2563

Co-authored-by: mcpiroman <38111589+mcpiroman@users.noreply.github.com>
2019-11-25 14:22:29 -08:00
Mike Griese 9ed3da8b3b
Decouple "Active Terminal" and "Focused Control" (#3540)
## Summary of the Pull Request

Unties the concept of "focused control" from "active control".

Previously, we were exclusively using the "Focused" state of `TermControl`s to determine which one was active. This was fraught with gotchas - if anything else became focused, then suddenly there was _no_ pane focused in the Tab. This happened especially frequently if the user clicked on a tab to focus the window. Furthermore, in experimental branches with more UI added to the Terminal (such as [dev/migrie/f/2046-command-palette](https://github.com/microsoft/terminal/tree/dev/migrie/f/2046-command-palette)), when these UIs were added to the Terminal, they'd take focus, which again meant that there was no focused pane.

This fixes these issue by having each Tab manually track which Pane is active in that tab. The Tab is now the arbiter of who in the tree is "active". Panes still track this state, for them to be able to MoveFocus appropriately. 

It also contains a related fix to prevent the tab separator from stealing focus from the TermControl. This required us to set the color of the un-focused Pane border to some color other that Transparent, so I went with the TabViewBackground. Panes now look like the following:

![image](https://user-images.githubusercontent.com/18356694/68697343-41ea2380-0544-11ea-8218-601b57fdd835.png)


## References

See also: #2046

## PR Checklist
* [x] Closes #1205
* [x] Closes #522
* [x] Closes #999
* [x] I work here
* [😢] Tests added/passed
* [n/a] Requires documentation to be updated

## Validation Steps Performed

Tested manually opening panes, closing panes, clicking around panes, the whole dance.

---------------------------------------------------

* this is janky but is close for some reason?

* This is _almost_ right to solve #1205

  If I want to double up and also fix #522 (which I do), then I need to also
  * when a tab GetsFocus, send the focus instead to the Pane
  * When the border is clicked on, focus that pane's control

  And like a lot of cleanup, because this is horrifying

* hey this autorevoker is really nice

* Encapsulate Pane::pfnGotFocus

* Propogate the events back up on close

* Encapsulate Tab::pfnFocusChanged, and clean up TerminalPage a bit

* Mostly just code cleanup, commenting

* This works to hittest on the borders

  If the border is `Transparent`, then it can't hittest for Tapped events, and it'll fall through (to someone)

  THis at least works, but looks garish

* Match the pane border to the TabViewHeader

* Fix a bit of dead code and a bad copy-pasta

* This _works_ to use a winrt event, but it's dirty

* Clean up everything from the winrt::event debacle.

* This is dead code that shouldn't have been there

* Turn Tab's callback into a winrt::event as well
2019-11-18 15:41:25 -06:00
Dustin L. Howett (MSFT) df26c677ef
Upgrade to Microsoft.UI.Xaml 2.2 (#3027)
* We had to move to the final API:
   * Items -> TabItems
   * Items.VectorChanged -> TabItemsChanged
   * TabClose -> TabCloseRequested
   * TabViewItem.Icon -> TabViewItem.IconSource
* TabRowControl has been converted to a ContentPresenter, which
  simplifies its logic a little bit.
* TerminalPage now differentiates MUX and WUX a little better
* Because of the change from Icon to IconSource in TabViewItem,
  Utils::GetColoredIcon needed to be augmented to support MUX IconSources.
  It was still necessary to use for WUX, so it's been templatized.
* I moved us from WUX SplitButton to MUX SplitButton and brought the
  style in line with the one typically provided by TabView.
* Some of our local controls have had their backgrounds removed so
  they're more amenable to being placed on other surfaces.
* I'm suppressing the TabView's padding.
* I removed a number of apparently dead methods from App.
* I've simplified the dragbar's sizing logic and eventing.
* The winmd harvester needed to be taught to not try to copy winmds for
  framework packages.
* We now only initialize the terminal once we know the size

Closes #1896.
Closes #444.
Closes #857.
Closes #771.
Closes #760.
2019-10-14 22:41:43 -07:00
Richard Szalay f4294b17d7 Clean up Pane (#2494)
* Merge pane splitting methods

Having separate Horizontal/Vertical versions made it hard to manage, and App.cpp already made use of Pane::SplitState so it made sense to have that be the descriminator

* Rename Tab::(Can)AddSplit to (Can)SplitPane to align with Pane methods

Split was used as a noun in Tab but a verb in Pane, which felt odd

* Remove unused local variable in Pane::_CanSplit

* Remove redundant 'else' branches in Pane

Improves readibility for all 'low hanging fruit' cases where the 'if' was returning.
2019-08-28 07:40:16 -07:00
Richard Szalay 09d79cb422 Prevent splitting panes into 0 width/height #2401 (#2450)
Fixes a crash that can occur when splitting pane that was so small that the target panes would have a width/height of 0, causing DxRenderer to fail when creating the device resources.

This PR prevents both the call to `App::AddHorizontal/VerticalSplit` and the creation of the `TermControl` if the split would fail.

Closes #2401

## Details

`App::_SplitPane` calls `focusedTab->CanAddHorizontalSplit/CanAddHorizontalSplit` before it initializes the `TermControl` to avoid having to deal with the cleanup. If a split cannot occur, it will simply return. 

**Question: Should we beep or something here?**

It then follows the same naming/flow style as the split operation, so: `Tab::CanAddHorizontalSplit -> Pane::CanSplitHorizontal ->Pane::_CanSplit`. The public pane methods will handle leaf/child the same as the current Split methods.

`_CanSplit` reuses existing logic like `_root.GetActualWidth/Height`, `Pane::_GetMinSize`, and the `Half` constant.

## Validation Steps Performed

1. Open a new tab
2. Attempt to split horizontally/vertically more than 6-8 times

Success: Pane will will eventually stop splitting rather than crashing the process.
2019-08-20 15:38:45 -07:00
Mike Griese 8999c661b2 Only update the icon of a tab it the icon actually _changed_ (#2376)
Fixes #1333.
Fixes #2329.
2019-08-14 16:12:14 -07:00
Carlos Zamora a08666b58e Accessibility: TermControl Automation Peer (#2083)
Builds on the work of #1691 and #1915 

Let's start with the easy change:
- `TermControl`'s `controlRoot` was removed. `TermControl` is a `UserControl`
  now.

Ok. Now we've got a story to tell here....

### TermControlAP - the Automation Peer
Here's an in-depth guide on custom automation peers:
https://docs.microsoft.com/en-us/windows/uwp/design/accessibility/custom-automation-peers

We have a custom XAML element (TermControl). So XAML can't really hold our
hands and determine an accessible behavior for us. So this automation peer is
responsible for enabling that interaction.

We made it a FrameworkElementAutomationPeer to get as much accessibility as
possible from it just being a XAML element (i.e.: where are we on the screen?
what are my dimensions?). This is recommended. Any functions with "Core" at the
end, are overwritten here to tweak this automation peer into what we really
need.

But what kind of interactions can a user expect from this XAML element?
Introducing ControlPatterns! There's a ton of interfaces that just define "what
can I do". Thankfully, we already know that we're supposed to be
`ScreenInfoUiaProvider` and that was an `ITextProvider`, so let's just make the
TermControlAP an `ITextProvider` too.

So now we have a way to define what accessible actions can be performed on us,
but what should those actions do? Well let's just use the automation providers
from ConHost that are now in a shared space! (Note: this is a great place to
stop and get some coffee. We're about to hop into the .cpp file in the next
section)


### Wrapping our shared Automation Providers

Unfortunately, we can't just use the automation providers from ConHost. Or, at
least not just hook them up as easily as we wish. ConHost's UIA Providers were
written using UIAutomationCore and ITextRangeProiuder. XAML's interfaces
ITextProvider and ITextRangeProvider are lined up to be exactly the same.

So we need to wrap our ConHost UIA Providers (UIAutomationCore) with the XAML
ones. We had two providers, so that means we have two wrappers.

#### TermControlAP (XAML) <----> ScreenInfoUiaProvider (UIAutomationCore)
Each of the functions in the pragma region `ITextProvider` for
TermControlAP.cpp is just wrapping what we do in `ScreenInfoUiaProvider`, and
returning an acceptable version of it.

Most of `ScreenInfoUiaProvider`'s functions return `UiaTextRange`s. So we need
to wrap that too. That's this next section...

#### XamlUiaTextRange (XAML) <----> UiaTextRange (UIAutomationCore)
Same idea.  We're wrapping everything that we could do with `UiaTextRange` and
putting it inside of `XamlUiaTextRange`.


### Additional changes to `UiaTextRange` and `ScreenInfoUiaProvider`
If you don't know what I just said, please read this background:
- #1691: how accessibility works and the general responsibility of these two
  classes
- #1915: how we pulled these Accessibility Providers into a shared area

TL;DR: `ScreenInfoUiaProvider` lets you interact with the displayed text.
`UiaTextRange` is specific ranges of text in the display and navigate the text.

Thankfully, we didn't do many changes here. I feel like some of it is hacked
together but now that we have a somewhat working system, making changes
shouldn't be too hard...I hope.

#### UiaTextRange
We don't have access to the window handle. We really only need it to draw the
bounding rects using WinUser's `ScreenToClient()` and `ClientToScreen()`. I
need to figure out how to get around this.

In the meantime, I made the window handle optional. And if we don't have
one....well, we need to figure that out. But other than that, we have a
`UiaTextRange`.

#### ScreenInfoUiaProvider
At some point, we need to hook up this automation provider to the
WindowUiaProvider. This should help with navigation of the UIA Tree and make
everything just look waaaay better. For now, let's just do the same approach
and make the pUiaParent optional.

This one's the one I'm not that proud of, but it works. We need the parent to
get a bounding rect of the terminal. While we figure out how to attach the
WindowUiaProvider, we should at the very least be able to get a bunch of info
from our xaml automation peer. So, I've added a _getBoundingRect optional
function. This is what's called when we don't have a WindowUiaProvider as our
parent.


## Validation Steps Performed
I've been using inspect.exe to see the UIA tree.
I was able to interact with the terminal mostly fine. A few known issues below.

Unfortunately, I tried running Narrator on this and it didn't seem to like it
(by that I mean WT crashed). Then again, I don't really know how to use
narrator other than "click on object" --> "listen voice". I feel like there's a
way to get the other interactions with narrator, but I'll be looking into more
of that soon. I bet if I fix the two issues below, Narrator will be happy.

## Miscellaneous Known Issues
- `GetSelection()` and `GetVisibleRanges()` crashes. I need to debug through
  these. I want to include them in this PR.

Fixes #1353.
2019-07-30 16:43:10 -07:00
Mike Griese 5074335392 Add a keybinding for ClosePane (#2012)
Closes #993
  When the last pane in a tab is closed, the tab will close.
  Bound to Ctrl+Shift+W by default. See #1417 for discussion on the default
  keybindings. The Ctrl+W->CloseTab keybinding is being removed in favor of
  ClosePane.
2019-07-18 17:23:40 -07:00
Mike Griese 8d52ba0990
Add support for moving focus between panes with the keyboard (#1910)
Enables the user to set keybindings to move focus between panes with the keyboard. 
This is highly based off the work done for resizing panes. Same logic applies - 
  moving focus will move up the panes tree until we find a pane to move the focus to.
2019-07-17 09:30:15 -05:00
Mike Griese 2de2f445c7
Enable resizing the panes with the keyboard. (#1207)
Adds the ability to resize panes with the keyboard. 

This is accomplished by making the Column/RowDefinitions for a Pane use `GridLengthHelper::FromPixels` to set their size. We store a pair of floats that represents the relative amount that each pane takes out of the parent pane. When the window is resized, we use that percentage to figure out the new size of each child in pixels, and manually size each column. 

Then, when the user presses the keybindings for resizePane{Left/Right/Up/Down}, we'll adjust those percentages, and resize the rows/cols as appropriate.

Currently, each pane adjusts the width/height by 5% of the total size at a time. I am not in love with this, but it works for now. I think when we get support for keybindings with arbitrary arg blobs, then we could do either a percent movement, or a number of characters at a time. The number of characters one would be trickier, because we'd have to get the focused control, and get the number of pixels per character, as adjacent panes might not have the same font sizes.
2019-07-10 08:27:12 -05:00
Dustin L. Howett (MSFT) e1ce8a5ed7
Move to Microsoft.UI.Xaml 2.2.109211001-prerelease (#1707)
Fixes #1265.
2019-06-28 18:03:43 -07:00
adiviness 9b92986b49
add clang-format conf to the project, format the c++ code (#1141) 2019-06-11 13:27:09 -07:00
Mike Griese 2da5b0b146
Add support for multiple panes in the same window (#825)
* Start working on adding support for panes

  See #1000 for the panes megathread on remaining work.

  The functionality will be there, but the keybinding won't be there, so people have to
  opt-in to it.
2019-06-07 16:56:44 -05:00
Kapperchino 1191a59681 Update scroll bar with scroll (#920)
* added another method to scroll with keyboard

* set lastscrolloffset to 0

* fixed unused variable

* renamed ViewPort to Viewport

* changed keyBoard to keyboard in the functions, and added expliantion for function
2019-05-23 13:39:29 -07:00
Hermès BÉLUSCA - MAÏTO acabbe0459 Fix it's versus its typo. (#911) 2019-05-21 06:15:44 +00:00
Dustin Howett d4d59fa339 Initial release of the Windows Terminal source code
This commit introduces all of the Windows Terminal and Console Host source,
under the MIT license.
2019-05-02 15:29:04 -07:00