Tutorials

These are detailed descriptions of specific features as addition for the "Sprocket in details" overview. Check out our blog for step-by-step tutorials.

Sandbox

By default, we disable the sandbox feature.

In this tutorial (guide?), we will show how to add the sandbox feature.

First, we will need a command line switch to enable the sandbox. Let’s add our switches file to the common directory, so we could access it from the entire application. Next, we need to define the switch: “use-sandbox”. By default, we disable the sandbox mode, and only enable it when the use-sandbox flag is set. The browser process will handle these command line flags.

Finally, we need to add the sandbox target, and here is a guide how to use it.

Now if we use the --use-sandbox command line argument, the application will run in sandboxed mode.

On Android, sandboxing is default. With version 4.1 (Jelly Bean), a new feature has been added to Android, it is called process isolation. Setting a process isolated means, that it will not have any permissions on its own, and it is isolated from the rest of the system. For instance an isolated process can only read the files / folders from the APK itself, but can not read any other data which is on the external or internal storage of the device. To sandbox a process on Android, you can set the android:isolatedProcess=true on the specified process. In Sprocket, this method is used for sandboxing.

Fullscreen support

Linux

To support fullscreen mode, first, some WebContentsDelegate methods should be overridden in our SprocketWebContents class. These methods are the following:

These methods are called from the Content API when a website requests to be (or not to be anymore) in full screen: for example when the fullscreen button is pressed on a HTMLVideoElement. In the Enter… and Exit… methods the resizing behaviors can be configured. Besides Content API requesting the fullscreen view, the user should be able to toggle fullscreen mode as well. In Sprocket, this is possible with pressing the F11 key. The key event gets catched in SprocketWebContents::HandleKeyboardEvent method and it is delegated to SprocketWindowDelegateView which does the handling.

There is another method which plays a key role in the full screen toggling: PlatformToggleFullscreenModeForTab. It is important to save the fullscreen state of the window, before toggling to fullscreen mode on a website, because after switching to non-fullscreen view, the same state as before should be restored. For example, when a video is being watched, the user can toggle the window to fullscreen mode, but not the video. After this, the user can toggle the video to fullscreen as well. After switching to a non-fullscreen video mode, it is important that the window stays fullscreen, because only the video was toggled. To solve this problem, we added a was_fullscreen variable to SprocketWindow’s implementation. Another common case is, when the user sets the window and the video to full screen at the same time. In this case, when the window fullscreen mode gets toggled off, the video (web content) should be toggled to normal mode as well. This logic is also implemented in PlatformToggleFullscreenModeForTab. The current states of the window and webcontents are kept in the is_fullscreen variable in SprocketWindow and SprocketWebContents.

The above description applies for all branches. The difference in the implementation between core (testing) and master branch is in SprocketWindowDelegateView class. This class is responsible for the UI layout.

So first, let’s see, how it works on core and testing branch, because it’s the simpler way. The window’s layout is a simple FillLayout, which is completely filled with the WebView. To toggle fullscreen mode it is enough to call SetFullscreen(bool fullscreen) on the windowWidget.

On master Sprocket, toggling fullscreen mode is more complicated because the task is not just to stretch a FillLayout to fullscreen, but to rearrange the whole layout in order to hide the toolbar, tabs, etc. To completely understand our solution, first you should have read the above Browser section. When fullscreen layout is requested, the gridView should be removed and replaced by the webView. When normal layout is requested, the webView is removed and replaced by the gridView.

Android

On Android, the case is much simpler, because toggling the browser window to fullscreen is not an option on mobile browsers, so we only have to deal with toggling of the webcontents which was already described in the Linux section above.

Tab support (Linux)

To support multiple browsing tabs, you can use the classes from ui/view/controls/tabbed_pane/. These classes contain the most important features regarding tab support, but they need some customization for the proper use. So the simplest way is to implement these classes yourself, so that you can keep the implemented features and extend them in your own way. Three classes play the key role in tab support: TabbedPane, Tab, TabStrip. TabbedPane contains a tab strip and the contents view. TabStrip contains the tabs as its child views, and the contents view's child views are the webviews associated with each tab.

TabStrip is just a simple View subclass which contains unique size and layout calculations.

Tab represents a tab with its header and content view (webview). It contains a reference to the tabbed pane which contains it, and also a reference to its associated content view. We also added a SprocketWebContents member to the Tab class so that it could keep track of its own web content (back, forward, stop, load URL, etc). If you prefer, you can also add a close button to the Tab, but then you should change the Layout() method. You can configure your tab's size in GetPreferredSize() function. You can use dynamically changing widths, or just use constants. If you're looking for a simple solution you can put the TabStrip into a ScrollView and return constant sizes in this method. Originally there is no accessor provided to Tab's title member, so dynamic title changes are not supported. You can provide a setter in order to support this.

TabbedPane is the class that is responsible for most of the tab related functions. It manages the tabs in the TabStrip and the associated content views. It ensures the non-null 1:1 relationship between content views and tabs. TabbedPane is responsible for tab additions, selections and closing. Tab closing is not supported originally, you can implement your custom function for it. Here you can find our example. If you added a close button to the Tab, you should extend the ButtonListener class in TabbedPane as well, and override ButtonPressed(...) method in order to catch the proper event. GetTabAt(int index) method is private originally, but it can be modified to be public, because in some cases it is necessary to call it from outside. We extracted the accelerator addition to a separate method called InitAccelerators(). In AcceleratorPressed(...) method you can bind other behaviours to specific key presses, but first you have to add the proper accelerator in InitAccelerators(). In order to get the window resizing to work correctly, PreferredSizeChanged() method should be overridden, and you should provide the correct size calculations of the tab associated webviews. In our case we set all of the tabs webview’s sizes to match the selected tab's webview's size. You should also modify GetPreferredSize() function: it's not necessary to calculate the maximum size of the content views, you can use the selected tab's content view's size. We added an extra button to the tabstrip for opening new tabs. If you do this our way, you should change the GetTabCount() method, because now tab_strip_->child_count() won't be equal to contents_->child_count(), you should write tab_strip_->child_count() - 1 instead. (Because the new tab button is also a child view of the tab strip, but has no associated content view.) You should also differentiate two cases in ButtonPressed() method, based on who the sender is (new tab or close tab button).

You should also remove the early return from SelectTabAt(int index), because it can create confusing situations in case of tab deletion (you delete a selected tab, and the tab that comes in place of the deleted should be selected, but the index stays the same). Also when implementing the tab closing you should take care of different cases (selected tab deletion, which tab can come to its place, unselected tab deletion). You should consider a unified behavior to simplify your implementation. In our case when a selected tab gets deleted and it has other tabs on the right, then the tab on its right will replace it, if it is the rightmost tab, then the tab on its left becomes selected. If unselected tab gets deleted then the selected tab remains the same.

As mentioned before you can choose to put the tab strip into a scroll view instead of dynamic tab width changing, that is what we are using as well. In this case you should take care of the proper size calculations in Layout(). In the scrollview size calculation you should consider different cases: tab scrollbar is shown or not. In the content view size calculation you should use the previously calculated scrollview height.

There is a fourth class that should be used, that's TabbedPaneListener. It is an abstract class so some of your own classes should extend it. TabbedPane has a reference to a listener and it can communicate with the rest of the application through it. Originally it has one method: TabSelectedAt(int index). When a tab gets selected, TabbedPane calls this method on it's listener, in order to perform certain operations depending on tab selection. We expanded the listener interface with two other methods: LastTabClosed() and OpenNewEmptyTab(). For example, the first method is necessary because it lets SprocketWindowDelegateView know that the last tab has been closed, so it can call specific methods in order to close the whole window.

Besides these classes you should also modify your existing code. You should add methods to the window class regarding tab addition and selection. Before implementing the tab support the SprocketWebContents instance belonged to the SprocketWindowDelegateView, now it should belong to the tab.

The navigation controls, URL bar and window title should also change in regard of the selected tab. Therefore you should check if the tab is selected before updating the navigation controls, setting the title or setting the text of the url bar.


© 2016 University of Szeged, DSE; Sprocket Team