If you use QWebView, do you know how make its background to be translucent? Apparently, the trick is not so well known, hence I decide to share it here.
Basically it boils down the following code snippet:
The first three lines set a new transparent brush for the page. This is necessary so that all the painting is blended properly. The last one ensures that the web view is not opaque, i.e. it does not paint all the pixels contained in its rectangle. Opaque paint event for QWebView is the default, most of the time you want to have a web page with typical normal background color, either set by the web page or something you specify as the fallback color.
If you combine QWebView see-through background with top-level widget opacity feature (see what Samuel wrote about this some time ago), you will get something like the following screenshot (the wallpaper image is Soft Green, from Valient Gough). Neat, isn’t it? Note that of course it requires a window system which supports composition, e.g. modern X11 window manager, recent versions of Windows, and so on.
As usual, the code for this short example is available from the git repository, just check the transparentweb subdirectory. Again, I already prepared both the Qt/C++ and Python (via PyQt) versions. Enjoy!
In the recent pre-release of Qt for S60 we have included a build of WebKit that compiles and runs on S60. This pre-release is an important milestone for this porting effort that started about half a year ago. Hence, I would like to briefly highlight a few things about it:
The main work is finding good solutions for quirks in the toolchain. That includes the ARM RVCT compiler and the Metrowerks compiler used by the emulator on Windows, both with their own unique set of challenges.
The team working on this consists of Norbert Leser and Laszlo Gombos from the Nokia Browser Team in Boston as well as Janne Koskinen from Digia and Kristian Amlie from the QtSoftware Team here in Oslo. In addition Ariya wrote the little but super-cool anomaly demo browser, which is included in the Qt/S60 Tower release. The port is still in early stages, but it’s looking quite good already and rather performant.
We’ve been maintaining the patches in separate repositories and we’ve been pushing patches in small steps upstream for a few months now. There’s still a lot to go, but things are progressing. And the result is looking really cool
As Ariya mentioned in one of his previous posts, we’ve been doing some work on using JavaScriptCore (JSC) as the QtScript back-end. The whole idea is that you’ll get the same QtScript API, but with JSC performance. There’s also the prospect of being able to use the QtScript API together with QtWebKit, giving a smooth integration (e.g. having a function similar to QWebFrame::evaluateJavaScript() that returns a QScriptValue rather than a QVariant, and being able to use QScriptValue::call() and QScriptValue::setProperty() and friends; in general, having such API will just make it much easier for the C++ side and JS side to communicate).
The main challenge we’re facing is keeping the QtScript API behave 100% as it does today; it’s not acceptable that the behavior changes just because us speed freaks decide to replace the back-end, of course. The main aid we have in this regard is the set of QtScript autotests; assuming the tests are all-encompassing (which, let’s face it, is hard to guarantee, but let’s pretend…), after completing the back-end swap, all the tests should still pass. Once this goal is reached, some brave soul would step forward, brown paper bag in hand, asserting that except for performance improvements, it’s not possible for the application developer to tell that the QtScript runtime was replaced. OK, so we’ll probably have to do some real-world testing as well.
Work on the back-end had been put on hold for some time due to various other projects, but now we’re slowly getting back in business again. And the best news is that the ongoing work is now out in the open (qtscript-jsc-backend branch)! Now before you start doing the Qt dance, just keep in mind that the branch is not currently in a state where it can be used to run new or existing apps against the back-end, because not all the API and/or behavior is implemented yet. Currently we’re working on bringing it up-to-date with the last few months of changes in WebKit trunk, then we can focus on remaining API. In case you’re interested in helping out hardcore hacker-style, though, there’s an easy recipe that we all follow: Run one of the qscript* autotests, look for failures or asserts that say “Implement me”, and hack on the implementation until the test passes. Test statement by test statement, the compatibility will get there. Happy hacking!
While planning for Developer Days 2008 I tried to wring something interesting out of my technically starved brain to show off to the crowds of hackers attending. At the time I had just noticed Twitter, a service that seemed to promise the value of Facebook without all the junk - seeing status updates from my friends and the ramblings from people I find interesting or useful from an academic perspective.
I started looking into the Twitter API and found that using Qt’s QNetworkAccessManager I could quickly create something powerful that interoperated with URL API’s. Attempting to be different, I decided that it wouldn’t be cool to create a UI based on traditional QWidgets, and definately too boring to simply browse twitter.com. So, using the Twitter API which returns XML data, QtXmlPattern’s XSLT support and a little bit of creative tinkering with exposing Qt native objects to QtWebKit, I ended up with a useful Twitter client that converted the XML data to UI.
After returning from Developer Days, we enlisted the help of Girish - a(n ex )Troll and Generally Great Guy who helped polish my haphazardly written demo-code into something beautiful and functional - as well as write a completely new example on how to integrate with YouTube! Girish also made some nice screencasts for our Qt 4.5 launch (source follows after);
And now we have finally pushed the two cool examples of QtWebKit that shows how easy and elegant it is to mixing web programming paradigms with native code in Qt! If you want to try it out, play with it, modify it, please head over to the Graphics Dojo and look for twitterview and videofeed. Happy hacking!
An interesting feature of a navigation system (so I was told, I don’t own a car) is the so-called "night mode". Basically the display is adjusted so that the text and the map become more readable under low ambient light condition. An easy trick to do this is by inverting the color, just like what Mac OS X can do for the whole desktop.
Thanks to QPainter, it is fairly easy to do that in just a few lines of code. Basically we need to use a proper composition mode. If you think composition modes are like black magic, here is a chance to understand a bit of it. As you read the documentation on QPainter::CompositionMode_Difference or CompositionMode_Exclusion, you will find that Painting with white inverts the destination color. Voila! That is exactly the cheating path that we have to use.
The super-short example for color inversion is in the Graphics Dojo repository under the webnightmode directory (available for both Qt/C++ and PyQt). Although the trick here is illustrated for QWebView, of course it is suitable for other widgets, too (see Henrik’s yesMan example). Note that not every paint engine/device supports QPainter::CompositionMode_Difference, hence why in the code I force the use of raster graphics system under X11.
Note that an actual implementation of a night-mode feature is likely more complicated than just a color inversion method (feel free to suggest or brainstorm the ideas for such an algorithm). The overall brightness and constrast should be taken into account. Likely this requires an adventure in the non-RGB color space, something that is outside the scope of this example. Most of the cases however, you can get away with the discussed trick.
Exercise for the brave readers: use selectors (CSS or jQuery) to find the map element, then invert that element only.
When you develop a web browser for a mobile platform, a D-pad or a mini trackball is usually the main in-page navigation input. In some browsers, going "down" scrolls the whole web page or jumps to the nearest (sensible) hyperlink. There is an interesting observation here. As you scroll to read e.g. a news site, your eyes are locked to the topmost part of the browser. Hence, a scrolling system that avoids "slicing" the content right at the top of the view will be useful. Your eyes are not distracted because it is easier to locate the "next-to-read" spot after the page scrolls.
If the above paragraph is not easy to understand, consider the following screenshot. Both windows show the mobile version of BBC News, after scrolling (I pressed the down arrow nine times). On the right side, the image is cut. On the left side however, the image is positioned so that it will be aligned properly. In fact, if I continue pressing down arrow key many times until I reach the section where there is no image anymore, it always scrolls and snaps each text line, which is very convenient as you read the text.
The example for doing this snap-scrolling is in the Graphics Dojo repository under the snapscroll directory (available for both Qt/C++ and PyQt). To keep the example as simple as possible, I implement the snapping when down arrow key is only. Ideally, you might want to handle e.g. the up arrow, as well as page up and page down. Furthermore, the snap threshold constant actually should be font size dependent to ensure smooth scrolling. If you try the code, sometimes it fails because it snaps only in one direction. If you really prefer the "magnet behavior" consider adding some intelligence to snap in both directions.
The code also shows how to find out the bounding boxes (of the DOM elements) in a particular area of interest QWebFrame::hitTestContent() (in Qt 4.6 we will have the full QWebElement solution for this). The code proves, it is sufficient (at least for this scrolling purpose) to check for a hit in several sample points in that area. Beside, if a 3×3 pixels image escapes our detection and will not be snapped, how does it matter anyway?
For any widget system, be it KDE4 Plasma, Mac OS X Dashboard, Yahoo! Widgets, Opera Widget, Google Gadgets, Microsoft Gadgets, and so on, weather applet is usually the typical example (beside a digital clock, an analog clock, or other variants of the clock). What is shown here is yet another little weather info tool, built using QtWebKit.
The idea came up when the other day I presented a challenge to myself: what is the shortest possible code that shows the weather, along with the forecasts for the next few days, for any places in the world? Usually this involves a lot of thinking. Thanks to Google however, the solution came instantly (avid Google users know this by heart). Hint: see the result of searching for "Weather in Oslo".
By smartly (some people call it cheating, though) combining this powerful Google service and a web rendering engine, the solution magically appears. Or rather it should not. Because by using magic, I will be unfair to my fellow (poor) software engineers, I decided to fire my Qt Creator and implemented the answer to that challenge the hard way, i.e. by actually doing it. The screenshot first:
The logic of the program is rather simple. Just loads the proper URL corresponding to the search for the weather, as if you would have typed in manually in your favorite web browser. After the web page shows up, find the DOM element that represents that information snippet (we are not interested in the search results lists), this is done using little jQuery-based JavaScript code. The web page is rendered to a pixmap, only the region of that DOM element is painted, and then the pixmap is shown.
The code is just one git clone (or git pull) away from the Graphics Dojo repository (yes, we are also moving to Gitorious). Check the subdirectory named gweather. You need Qt at least version 4.5.
As healthy exercises for the readers, try the following things. Implement an auto-reload feature (be gentle, no need to refresh the page every 5 minutes). In addition, add a possibility to change the location or city. Remember, magic is not allowed.
Any tools which can save the developers the cost of headache pills are always valuable. For web development, JavaScript frameworks such as Prototype and jQuery (and many other similar ones) are these valuable tools. Just for doing content manipulation via JavaScript, using jQuery instead of the standard DOM API would save many precious working hours. No wonder they become so popular these days. Nokia packs jQuery for its Web Run Time, Microsoft bundles it with ASP.NET AJAX.
The QtWebKit team at Qt Software often gets the question like "Can I use jQuery in QtWebKit?". Since QtWebKit is just a normal web-rendering engine, of course the answer is "Yes". To get your feet wet quickly for using the deadly combination of QtWebKit and jQuery, continue reading and examine the demo presented in the following explanation.
There are two ways you can jQuerify your HTML content. If you have total control over the content that you want to display (e.g. using QWebView to display help or other rich-text), then you can refer jQuery directly in the HTML, i.e. inserting the proper <script> referring to the jQuery JavaScript code. If you don’t have a control over the content that you want to display (e.g. using QWebView for a web browser), then the best bet is to inject the jQuery JavaScript code. This can be carried out using QWebFrame::evaluateJavaScript. A nice place to do is after the document is fully loaded. The drawback is that you can’t do any manipulation while loading is in progress, but hey, you don’t have a control over the content anyway.
There are also two methods to pass the jQuery JavaScript code. For convenient access, you may want to store it as a file in the resource, thus it will be shipped along with your application. After that, the code can be referred from within QtWebKit using the qrc:/ URL, i.e. <script src="qrc:/jQuery.js">. If your application is pure web-based or an online hybrid C++/web, you can also source the script from e.g. Google AJAX libraries or using the network access manager to retrieve it (see the previous Monster example for similar trick). This means downloading the script at run-time (eating the bandwidth), but then you get the benefit of automatically update (zero-cost deployment). Judge it based on your needs, which trade-off suits you better.
Without further ado, the code is available in Graphics Dojo repository (no time to git-pull? download the gzipped archive), under the directory fancybrowser. You need Qt 4.5 to build the example. It is basically a normal minimalistic web browser with two extra buttons: to toggle the images upside down and to perform several actions, notably to highlight all links and removing certain types of elements.
Imagine if we would have to implement the same function using DOM API.
Careful readers might notice that the rotation is effect is achieved through two cool features implemented in WebKit: CSS Animation and CSS Transform. If you check out the rotateImages() function, it is also as simple as 7 lines of code. Couldn’t be simpler.
So far so good. But then, Qt 4.6 will sport QWebElement, as Tor Arne recently blogged about. Although it is not replacement for jQuery, for most cases this new element API allows a wide range of content manipulation. It is based on the concept of CSS 3 Selectors, whose query language is surprisingly very similar to jQuery. QWebElement was relatively easy to implement, in particular because WebKit supports CSS 3 Selectorsince some time already (thanks to David Smith for the implementation).
Although 4.6 is still not on the horizon yet, I modified the example demo to be able to use QWebElement when you build it with Qt > 4.5 (thus, after 4.6 will be released sometime in future, come back and recompile the demo). It is of course no magic that the code change is pretty minimal, in fact the implementation is very similar. For example, here is highlightAllLinks() function implemented using QWebElement (compare it to the previous jQuery flavor):
(As you can witness above, we even went so far to implement the necessary iterator, then foreach works flawlessly!)
As an exercise for the reader, implement a new functionality to undo the highlighting of links. For this to work, you need to change the highlighting code to use a new class (in the context of CSS class, not C++ class), instead of just modifying the background color of the link elements. You need to inject the suitable class definition into the stylesheet as well. Removing the highlighting is then as easy as removing the class from each of the link elements.
Seems nobody is interested in free drinks these days. At last that is my impression since not many guesses have been thrown for the title of this episode. Of course, that could also mean that this monster series is really boring anyway.
Whatever the case, here I present you the third and the latest episode of the Monsterwalker family saga. For those who missed the previous two episodes: The QtScript Menace and Attack of the SquirrelFish, I suggest reading them first to get the clue of the context. It’s merely about running Monster Evolution, part of the Chrome Experiments, written by Dean. As I have hinted before, now we make a radical move. After using Qt Script and JavaScriptCore in the first and second episode, respectively, now we are going to use V8, the fast JavaScript engine behind Google Chrome.
Using V8 means that we have to deal with the bindings manually. With Qt Script, we have the luxury of using its built-in Qt integration. Same goes with JavaScriptCore, we have the hook via QWebFrame. For V8, we need to go low-level and invoke the necessary V8 functions ourselves. Fortunately, V8 is already designed with embedding usage in mind.
Can’t wait to see the code? Check out the git repository under cymonster subdirectory. Grab the archive (find the snapshot link) if you do not use git. Make sure to open the README file and follow the instructions there, this is absolutely mandatory as this code requires a working V8 shared library. Don’t be shocked to see that the code is still as short as the previous examples. Despite our use of V8, the book-keeping and binding parts are kept to minimum.
Since V8 is claimed to have a fantastic performance, don’t be surprised if now you will a very fast rotating monster, unlike in the previous episodes. Typically you should easily reach 25 fps in modern machines these days. For the fun of it, the frame rate is capped at 50 fps (I didn’t bother to do it in the previous episodes, it won’t be reachable anyway). On a high-end machine with fast graphics card and running the demo with OpenGL graphics system, a stunning 30 fps is not so uncommon. If you follow this series faithfully and try all these three episodes, care to share the frame rate you got from each of the episodes?
As a side note, the use of OpaquePaintEvent to avoid offscreen buffer (since we stick to SourceOver composition mode all the time) seems to work only on Windows and Linux/X11, the latter often also depends on the composition manager and good graphics driver, or a combination thereof. Thus, I decided to enable the use of offscreen buffer for Mac OS X. You can still enable it by hand on other platforms if you experience the lack of said effect. Mind you, this would cost you few fps, but that is the price you need to pay.
Last but not least, writing this monster series has been the source of fun and learning for me. I hope you enjoy reading it as much as I enjoy preparing it. May the Script be with you!
The final FAQ:
Q: Since V8 is so fast, don’t you want a V8-based Qt Script?
A: No, since JavaScriptCore is still the official JavaScript engine for WebKit. In addition, there are other reasons that I won’t elaborate here (to mention one: lack of a bytecode interpreter for non JIT-supported platforms).
Q: But you use it already in this example?
A: To use V8 is different that to build a full-blown Qt Script implementation using V8. The former is a fun hacking session for one afternoon, the latter is a real engineer project that spans weeks.
Q: Will there be The Monkey Traces Back?
A: Unlikely, I am exhausted.
Postscript: No monsters were harmed in the making of these demos.
One of the main missing parts of QtWebKit so far has been a proper way to inspect and manipulate the document structure. In JavaScript this is provided by the Document Object Model (DOM) bindings — giving you methods like getElementById(), createElement(), and insertBefore(). These methods were also accessible in Qt 4.4 and 4.5 though QWebFrame::evaluateJavaScript(), but it was hardly a optimal way of working with the document.
The reason a proper API for this was deferred in the earlier versions of QtWebKit was because we wanted to provide an API that was not only powerful, but also easy to use. That left out using QDom, or a similar exhaustive API, as customer feedback has shown that writing code on that level can be both tedious and error prone.
Traversing the DOM like this quickly becomes hairy. The same pattern can be found in JavaScript code: using getElementById(), traversing children, looking for a element of a certain type, etc.
Another typical use case is manipulation, where you would do something like:
Remember to keep your tongue straight when building that insertAfter() statement!
Now some of you are probably jumping on your chairs now, screaming “this is not how you would do it in JavaScript!”. And you’re right, the JavaScript world has found a way to shield off the above annoyances: wrapper libraries like jQuery and Prototype.
Taking inspiration from these libraries we did a one-day prototyping/hacking session back in November, and the results were promising. We also asked customers what they really meant when they were asking for a DOM API, and it turned out that the goal was to inspect and manipulate the DOM, but not necessarily though a one-to-one mapping of the API provided by the DOM specification. Last week we managed to reserve some cycles to continue the work, and we’re now ready for some feedback.
So how does the new shiny QtWebKit DOM API look? There’s two classes: QWebElement and QWebElementSelection.The former wraps a DOM Element, and has methods for manipulation and traversal. The latter is just a list of QWebElements, which can be iterated and extended. The frosting lies in the way elements are selected: using CSS3 selector syntax (similar to jQuery). The implementation of the selectors is already part of WebKit, so we’re basically building on a tried and tested code base.
Using the two snippets above as examples, they would become:
The initial implementation of the new API is already landed in trunk, so feel free to try it out. You can find the API documentation here, but please note that this is a work in progress, so the API may change.
Oh, and here’s a screenshot of the QtLauncher highlighting all links: