Editing Using Fremantle widgets
Warning: You are not logged in.
Your IP address will be recorded in this page's edit history.
The edit can be undone.
Please check the comparison below to verify that this is what you want to do, and then save the changes below to finish undoing the edit.
Latest revision | Your text | ||
Line 1: | Line 1: | ||
- | This document should help developers to port the user interface from | + | This document should help developers to port the user interface from Diablo to Fremantle. The document mirrors what was discussed on the mailing lists, forum and bug reports. It is based completely on the Fremantle Beta SDK which is the most recent SDK at the moment. |
+ | in addition, please check the growing [http://wiki.maemo.org/index.php?title=Documentation/Maemo_5_Developer_Guide/Human_Interface_Guidelines Human Interface Guidelines] and the official hildon documentation: | ||
* [http://www.forum.nokia.com/info/sw.nokia.com/id/eb8a68ba-6225-4d84-ba8f-a00e4a05ff6f/Hildon_2_2_UI_Style_Guide.html Hildon 2.2 UI Style Guide] | * [http://www.forum.nokia.com/info/sw.nokia.com/id/eb8a68ba-6225-4d84-ba8f-a00e4a05ff6f/Hildon_2_2_UI_Style_Guide.html Hildon 2.2 UI Style Guide] | ||
* [http://www.forum.nokia.com/info/sw.nokia.com/id/019c2b31-3777-49a0-9257-970d79580756/Hildon_2_2_Widget_UI_Specification.html Hildon 2.2 Widget UI Specification] | * [http://www.forum.nokia.com/info/sw.nokia.com/id/019c2b31-3777-49a0-9257-970d79580756/Hildon_2_2_Widget_UI_Specification.html Hildon 2.2 Widget UI Specification] | ||
Line 6: | Line 7: | ||
Please feel totally free to add/update/change/remix this document. Many aspects are currently not discussed here but will hopefully be added by you! | Please feel totally free to add/update/change/remix this document. Many aspects are currently not discussed here but will hopefully be added by you! | ||
- | Note: The casts of all code examples | + | Note: The casts of all code examples haven been removed for better readability. |
- | |||
+ | = Toggle Buttons Vs. Radio Buttons = | ||
The use of radio buttons in Fremantle is discouraged because they don't fit the visual style quite well. Instead you should use toggle buttons. | The use of radio buttons in Fremantle is discouraged because they don't fit the visual style quite well. Instead you should use toggle buttons. | ||
Line 15: | Line 16: | ||
Example: | Example: | ||
- | < | + | <pre> |
GtkWidget *b1 = gtk_radio_button_new_with_label("One"); | GtkWidget *b1 = gtk_radio_button_new_with_label("One"); | ||
GtkWidget *b2 = gtk_radio_button_new_with_label_from_widget(b1, "Two"); | GtkWidget *b2 = gtk_radio_button_new_with_label_from_widget(b1, "Two"); | ||
gtk_toggle_button_set_mode(b1, FALSE); | gtk_toggle_button_set_mode(b1, FALSE); | ||
gtk_toggle_button_set_mode(b2, FALSE); | gtk_toggle_button_set_mode(b2, FALSE); | ||
- | </ | + | </pre> |
+ | |||
[[Image:Fle_tut_radio_buttons.jpg|frame|Above you see how radio buttons are displayed in Fremantle. There is a bug in this screenshot, normally of course only one of the four options would be selected.]] | [[Image:Fle_tut_radio_buttons.jpg|frame|Above you see how radio buttons are displayed in Fremantle. There is a bug in this screenshot, normally of course only one of the four options would be selected.]] | ||
Line 26: | Line 28: | ||
[[image:Fle_tut_toggle_buttons.jpg|frame|Here you can see four radio buttons which are displayed as toggle buttons using the <code>gtk_toggle_button_set_mode()</code> function mentioned above.]] | [[image:Fle_tut_toggle_buttons.jpg|frame|Here you can see four radio buttons which are displayed as toggle buttons using the <code>gtk_toggle_button_set_mode()</code> function mentioned above.]] | ||
- | + | = Widget Sizes = | |
- | + | ||
For some widgets there is now an enum which provides three different values: <code>HILDON_SIZE_FINGER_HEIGHT</code>, <code>HILDON_SIZE_THUMB_HEIGHT</code> and <code>HILDON_SIZE_AUTO_HEIGHT</code>. You can use them, for example, like that: | For some widgets there is now an enum which provides three different values: <code>HILDON_SIZE_FINGER_HEIGHT</code>, <code>HILDON_SIZE_THUMB_HEIGHT</code> and <code>HILDON_SIZE_AUTO_HEIGHT</code>. You can use them, for example, like that: | ||
- | < | + | <pre> |
GtkWidget but* = hildon_gtk_button_new(HILDON_SIZE_FINGER_HEIGHT); | GtkWidget but* = hildon_gtk_button_new(HILDON_SIZE_FINGER_HEIGHT); | ||
- | </ | + | </pre> |
- | You should always use the finger or the thumb size, don't use | + | You should always use the finger or the thumb size, don't use HILDON_SIZE_AUTO_HEIGHT as the outcome is not totally clear (see below for screenshots). |
If you have a button where you cannot provide a size with the constructor, for example, a stock button, then you can use <code>hildon_gtk_widget_set_theme_size()</code> to set the code afterwards. Like in this small example: | If you have a button where you cannot provide a size with the constructor, for example, a stock button, then you can use <code>hildon_gtk_widget_set_theme_size()</code> to set the code afterwards. Like in this small example: | ||
- | < | + | <pre> |
GtkWidget *but = gtk_button_new_from_stock(GTK_STOCK_COPY); | GtkWidget *but = gtk_button_new_from_stock(GTK_STOCK_COPY); | ||
hildon_gtk_widget_set_theme_size(but, HILDON_SIZE_THUMB_HEIGHT); | hildon_gtk_widget_set_theme_size(but, HILDON_SIZE_THUMB_HEIGHT); | ||
- | </ | + | </pre> |
- | Now to get a feeling for the different sizes here are some screenshots that show a | + | Now to get a feeling for the different sizes here are some screenshots that show a HildonEntry together with a GtkButton using different sizes. |
- | [[Image:Fle_tut_button_auto_finger.jpg|frame|A | + | [[Image:Fle_tut_button_auto_finger.jpg|frame|A HildonEntry with HILDON_SIZE_AUTO_HEIGHT and a GtkButton with HILDON_SIZE_FINGER_HEIGHT. Looks inconsistent.]] |
- | [[Image:Fle_tut_button_finger_finger.jpg|frame|Both widget with | + | [[Image:Fle_tut_button_finger_finger.jpg|frame|Both widget with HILDON_SIZE_FINGER_HEIGHT. Looks more consistent now.]] |
- | [[Image:Fle_tut_button_finger_thumb.jpg|frame|For comparison reasons the HildonEntry with | + | [[Image:Fle_tut_button_finger_thumb.jpg|frame|For comparison reasons the HildonEntry with HILDON_SIZE_FINGER_HEIGHT and the GtkButton with HILDON_SIZE_THUMB_HEIGHT.]] |
- | + | = Window Menu = | |
- | + | In Fremantle it is not encouraged to use <code>GtkMenu</code> as window menu anymore. Instead you should use the <code>HildonAppMenu</code>. This new menu is really different from the old one so it´s worth taking a closer look. Here are the main features of the HildonAppMenu. | |
- | In Fremantle it is not encouraged to use <code>GtkMenu</code> as window menu anymore. Instead you should use the <code>HildonAppMenu</code>. This new menu is really different from the old one so it´s worth taking a closer look. Here are the main features of the | + | |
* It has big / finger friendly menu items. | * It has big / finger friendly menu items. | ||
* It holds a maximum of ten menu items. | * It holds a maximum of ten menu items. | ||
Line 60: | Line 60: | ||
* In portrait mode the menu items are automatically displayed in one row. | * In portrait mode the menu items are automatically displayed in one row. | ||
* There are no separators, so you cannot group your menu items. | * There are no separators, so you cannot group your menu items. | ||
- | * The menu items are | + | * The menu items are GtkButtons and not GtkMenuItems. |
- | The | + | The HildonAppMenu is meant to be displayed when the user clicks the title bar of the window, but it is possible to have several other HildonAppMenus in your application and activate them for example on button press. |
- | As you can see the | + | As you can see the HildonAppMenu differs quite a lot from the old GtkMenu. The main difference is surely that you cannot have more then 10 menu items |
+ | inside the new menu. The Hildon HIG gives an overview on how to deal with that. | ||
- | [[Image:Fle_tut_app_menu_with_filters.jpg|frame|A | + | [[Image:Fle_tut_app_menu_with_filters.jpg|frame|A HildonAppMenu with two filters at the top and four buttons]] |
== Using HildonAppMenu with GtkActions == | == Using HildonAppMenu with GtkActions == | ||
- | + | As said earlier, the menu items are not GtkMenuItems anymore but instead they are normal GtkButtons. So you´re using GtkActions in your code, you´ll probably miss a replacement for <code>gtk_action_create_menu_item()</code>. There is no direct replacement, instead you just have to use standard gtk functions to connect the button as a proxy to the action. Here is an example: | |
- | As said earlier, the menu items are not | + | <pre> |
- | < | + | |
GtkButton *menu_item = gtk_button_new(); | GtkButton *menu_item = gtk_button_new(); | ||
gtk_action_connect_proxy(action, menu_item); | gtk_action_connect_proxy(action, menu_item); | ||
- | </ | + | </pre> |
- | This is also possible with <code>GtkToggleAction</code> and <code>GtkRadioAction</code>. But remember that your | + | This is also possible with <code>GtkToggleAction</code> and <code>GtkRadioAction</code>. But remember that your GtkRadioButtons should look like GtkToggleButtons as mentioned above. So a complete example for a HildonAppMenu that should display three GtkRadioActions would look like this: |
- | < | + | <pre> |
GSList *group = NULL; | GSList *group = NULL; | ||
GtkAction *a1, *a2, *a3; | GtkAction *a1, *a2, *a3; | ||
Line 115: | Line 115: | ||
hildon_app_menu_append(menu, b2); | hildon_app_menu_append(menu, b2); | ||
hildon_app_menu_append(menu, b3); | hildon_app_menu_append(menu, b3); | ||
- | </ | + | </pre> |
- | + | ||
- | + | ||
+ | = Finger Friendly GtkTreeView = | ||
To get a finger friendly <code>GtkTreeView</code> it´s not enough to call <code>hildon_gtk_tree_view_new()</code> instead of <code>gtk_tree_view_new()</code> but you also have to put the tree view inside a <code>HildonPannableArea</code> to get finger friendly sizes. If you have your tree view inside a <code>GtkScrolledWindow</code> it will be displayed with stylus-style (like in Diablo). | To get a finger friendly <code>GtkTreeView</code> it´s not enough to call <code>hildon_gtk_tree_view_new()</code> instead of <code>gtk_tree_view_new()</code> but you also have to put the tree view inside a <code>HildonPannableArea</code> to get finger friendly sizes. If you have your tree view inside a <code>GtkScrolledWindow</code> it will be displayed with stylus-style (like in Diablo). | ||
- | Also if you´re displaying icons in your tree view you probably should use the | + | Also if you´re displaying icons in your tree view you probably should use the 40x40 pixel version for Fremantle if you used the 26x26 pixel version in Diablo. |
- | + | ||
- | + | ||
+ | == Normal Vs. Edit Mode == | ||
There are now two different modes for the tree view. Those modes affect how the rows in a tree view react to finger taps. | There are now two different modes for the tree view. Those modes affect how the rows in a tree view react to finger taps. | ||
Line 131: | Line 129: | ||
If the user should be able to select or edit rows then you should use <code>HILDON_UI_MODE_EDIT</code>. | If the user should be able to select or edit rows then you should use <code>HILDON_UI_MODE_EDIT</code>. | ||
- | + | == Using Filters For Sorting == | |
- | + | ||
Most of you probably are using the tree view with a header row that displays column labels. Often this header row can also be used to sort the columns ascending or descending. If you're designing a finger friendly UI you will usually have a very limited number of visible columns - probably only one or two. In this case the column content is often self explanatory and the header row is only there for sorting. If that's the case for your UI, you might want to remove the header column completely and replace it with so called filters on the HildonAppMenu. | Most of you probably are using the tree view with a header row that displays column labels. Often this header row can also be used to sort the columns ascending or descending. If you're designing a finger friendly UI you will usually have a very limited number of visible columns - probably only one or two. In this case the column content is often self explanatory and the header row is only there for sorting. If that's the case for your UI, you might want to remove the header column completely and replace it with so called filters on the HildonAppMenu. | ||
According to the HIG filters are meant to change how data is presented, but it should not affect the amount of data that is displayed. Sorting a tree view would be a possible use case. To do this, just have a look at the example: | According to the HIG filters are meant to change how data is presented, but it should not affect the amount of data that is displayed. Sorting a tree view would be a possible use case. To do this, just have a look at the example: | ||
- | < | + | <pre> |
/* Remove the header row */ | /* Remove the header row */ | ||
gtk_tree_view_set_headers_visible(view, FALSE); | gtk_tree_view_set_headers_visible(view, FALSE); | ||
Line 152: | Line 149: | ||
hildon_app_menu_add_filter(menu, b1); | hildon_app_menu_add_filter(menu, b1); | ||
hildon_app_menu_add_filter(menu, b2); | hildon_app_menu_add_filter(menu, b2); | ||
- | </ | + | </pre> |
That is all for showing them on the window menu. Now only a callback is needed which gets activated whenever the user selects a filter. An example implementation might look like that: | That is all for showing them on the window menu. Now only a callback is needed which gets activated whenever the user selects a filter. An example implementation might look like that: | ||
- | < | + | <pre> |
void on_sort_filter_clicked(GtkToggleButton *button, GtkTreeSortable *sortable) | void on_sort_filter_clicked(GtkToggleButton *button, GtkTreeSortable *sortable) | ||
{ | { | ||
Line 162: | Line 159: | ||
} | } | ||
} | } | ||
- | </ | + | </pre> |
You can add as many filters as you like, but they will be displayed all in one row and there is no possibility to add another filter row. This means you have to select carefully what to put there and also have a look at the length of the strings. | You can add as many filters as you like, but they will be displayed all in one row and there is no possibility to add another filter row. This means you have to select carefully what to put there and also have a look at the length of the strings. | ||
Line 183: | Line 180: | ||
[[Image:Fle_tut_filter_long_strings.jpg|frame|Long strings get truncated]] | [[Image:Fle_tut_filter_long_strings.jpg|frame|Long strings get truncated]] | ||
- | + | = Context Menus = | |
- | + | ||
To display finger friendly context menues there is a hildon helper function called <code>hildon_gtk_menu_new()</code>. Just call this instead of <code>gtk_menu_new()</code> and you´re done. | To display finger friendly context menues there is a hildon helper function called <code>hildon_gtk_menu_new()</code>. Just call this instead of <code>gtk_menu_new()</code> and you´re done. | ||
Example: | Example: | ||
- | < | + | <pre> |
GtkWidget *menu = hildon_gtk_menu_new(); | GtkWidget *menu = hildon_gtk_menu_new(); | ||
Line 199: | Line 195: | ||
gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 0, | gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 0, | ||
gtk_get_current_event_time()); | gtk_get_current_event_time()); | ||
- | </ | + | </pre> |
- | ''Note that in the Beta SDK there is a bug. If you´re using <code> | + | ''Note that in the Beta SDK there is a bug. If you´re using <code>GtkImageMenuItems</code> instead of <code>GtkMenuItems</code> the menu will have stylus-style. This bug is already fixed and a work around is available here: https://bugs.maemo.org/show_bug.cgi?id=4654 .'' |
[[Image:Fle_tut_context_menu.jpg|frame|Finger friendly context menu which is showing four stock items]] | [[Image:Fle_tut_context_menu.jpg|frame|Finger friendly context menu which is showing four stock items]] | ||
- | + | = Panning = | |
- | + | ||
Almost all of you will know the problems with scrollbars in Diablo. You can have small scrollbars which are not finger friendly or you can have large scrollbars which are using a lot of screen space and look ugly. | Almost all of you will know the problems with scrollbars in Diablo. You can have small scrollbars which are not finger friendly or you can have large scrollbars which are using a lot of screen space and look ugly. | ||
Line 211: | Line 206: | ||
<code>HildonPannableArea</code> can be used as a replacement for <code>GtkScrolledWindow</code> but there are things you have to keep in mind when doing so. | <code>HildonPannableArea</code> can be used as a replacement for <code>GtkScrolledWindow</code> but there are things you have to keep in mind when doing so. | ||
- | + | == GtkTextView Inside HildonPannableArea == | |
+ | Panning does not work with a <code>GtkTextView</code>. Instead you can use a <HildonTextView> which is a drop in replacement. The advantage is, that then panning is possible. The disadvantage is that selecting text is not possible anymore. The discussion about this is here: https://bugs.maemo.org/show_bug.cgi?id=4619 | ||
- | + | == GtkHtml Inside HildonPannableArea == | |
+ | When using <code>GtkHtml</code> inside a <code>HildonPannableArea</code> the panning is not smooth. The problem seems to be that GtkHtml provides some build in support for panning and that it conflicts with the panning offered by Hildon. See this bug report here: https://bugs.maemo.org/show_bug.cgi?id=4631 | ||
- | |||
- | |||
- | |||
- | |||
- | |||
+ | = Portrait Mode = | ||
If your application should work in portrait mode you probably have to change the UI quite a bit. There are a couple of problems you'll might have: | If your application should work in portrait mode you probably have to change the UI quite a bit. There are a couple of problems you'll might have: | ||
* The toolbar is not wide enough to hold all items anymore. | * The toolbar is not wide enough to hold all items anymore. | ||
* The columns of your tree view get too small. | * The columns of your tree view get too small. | ||
- | * You cannot enter text because there´s no onscreen keyboard. | + | * You cannot enter text because there´s no onscreen keyboard. |
* Dialogs are not shown correctly (see https://bugs.maemo.org/show_bug.cgi?id=4618 ). | * Dialogs are not shown correctly (see https://bugs.maemo.org/show_bug.cgi?id=4618 ). | ||
* Probably more... | * Probably more... | ||
Line 230: | Line 223: | ||
This means you have to listen to changes in the orientation and hide/show/change widgets to make the UI functional in portrait mode. | This means you have to listen to changes in the orientation and hide/show/change widgets to make the UI functional in portrait mode. | ||
- | [[Image:Fle_tut_app_menu_portrait.jpg|frame|The | + | [[Image:Fle_tut_app_menu_portrait.jpg|frame|The HildonAppMenu with filters in portrait mode. The final version will cover the complete screen width, so there is a bit more space for the filters.]] |
- | + | == Listening To Screen Orientation Changes == | |
+ | Basically here you´re not listening to changes in the devices orientation, but you check the height and width of the screen. So if width > height you are in landscape mode and if height > width you´re in portrait mode. This is supposed to work no matter why height and width changed. So it does not depend on hardware support like acceleratormeters it could also just be a software setting that rotates the screen. | ||
- | + | <pre> | |
- | + | ||
- | < | + | |
gboolean is_portrait() | gboolean is_portrait() | ||
{ | { | ||
Line 259: | Line 251: | ||
} | } | ||
} | } | ||
- | </ | + | </pre> |
- | + | ||
Then inside your UI code you should listen to the <code>size-changed</code> signal of <code>GdkScreen</code>. For example: | Then inside your UI code you should listen to the <code>size-changed</code> signal of <code>GdkScreen</code>. For example: | ||
- | < | + | <pre> |
g_signal_connect(screen, "size-changed", on_orientation_changed, widget); | g_signal_connect(screen, "size-changed", on_orientation_changed, widget); | ||
- | </ | + | </pre> |
- | + | ||
- | + | ||
+ | == Testing Screen Orientation Changes In Scratchbox == | ||
For testing your code you can execute the following commands outside scratchbox: | For testing your code you can execute the following commands outside scratchbox: | ||
<pre> | <pre> | ||
Line 274: | Line 264: | ||
</pre> | </pre> | ||
- | |||
+ | == Automatic Screen Rotation == | ||
Your application is not automatically rotated when the user rotates its device. Even if the hardware supports it. There are more things to do to make that happen. Basically you have to do two things: | Your application is not automatically rotated when the user rotates its device. Even if the hardware supports it. There are more things to do to make that happen. Basically you have to do two things: | ||
* During startup of your application, or better shortly before showing the first window, you should check the orientation of the device and adjust your application. | * During startup of your application, or better shortly before showing the first window, you should check the orientation of the device and adjust your application. | ||
Line 281: | Line 271: | ||
Whether or not your application is rotated depends on a couple of things: | Whether or not your application is rotated depends on a couple of things: | ||
- | * There are two | + | * There are two flags which you can set on your windows. Those flags tell the system what to do. |
- | + | ** <tt>HILDON_PORTRAIT_MODE_SUPPORT</tt> tells the system that your application can be rotated, so it won't prevent any other application from rotating. | |
- | ** < | + | ** <tt>HILDON_PORTRAIT_MODE_REQUEST</tt> tells the system that your application wants to be rotated. |
- | ** < | + | |
* Rotation only happens when all visible windows are ok with being rotated. | * Rotation only happens when all visible windows are ok with being rotated. | ||
- | That means that to get a rotated desktop all visible windows must have the < | + | That means that to get a rotated desktop all visible windows must have the <tt>HILDON_PORTRAIT_MODE_SUPPORT</tt> flag set and at least one application must have the <tt>HILDON_PORTRAIT_MODE_REQUEST</tt> flag set. |
- | It's important that you set the flags correctly on all windows that you open. If you or another application opens a window with the < | + | It's important that you set the flags correctly on all windows that you open. If you or another application opens a window with the <tt>HILDON_PORTRAIT_MODE_SUPPORT</tt> flag not set, the whole UI is rotated to landscape mode. |
So here are the steps you have to do to make correct use of the portrait mode: | So here are the steps you have to do to make correct use of the portrait mode: | ||
- | * On all windows that support portrait mode, set the < | + | * On all windows that support portrait mode, set the <tt>HILDON_PORTRAIT_MODE_SUPPORT</tt> flag. |
- | * During startup check the hardware orientation. If the hardware orientation is portrait mode, then set the < | + | * During startup check the hardware orientation. If the hardware orientation is portrait mode, then set the <tt>HILDON_PORTRAIT_MODE_REQUEST</tt> flag on at least one visible window. |
- | * While running your application, listen to changes in the orientation of the device. If it is rotated to landscape mode set the < | + | * While running your application, listen to changes in the orientation of the device. If it is rotated to landscape mode set the <tt>HILDON_PORTRAIT_MODE_SUPPORT</tt> flag. If it's rotated to portrait mode set the <tt>HILDON_PORTRAIT_MODE_REQUEST</tt> flag. There is no need to set both flags as 'request' also implies 'support'. |
- | + | ||
- | |||
- | In order to find out whether or not the device currently is in portrait you need to ask the MCE (Mode Control Entity) via | + | === Finding Out The Current Hardware Orientation === |
+ | In order to find out whether or not the device currently is in portrait you need to ask the MCE (Mode Control Entity) via DBus. The parameters of the call are the following and can be found as constants in 'mce/dbus-names.h'. | ||
- | + | <pre> | |
- | + | Service: "com.nokia.mce" | |
- | + | Path: "/com/nokia/mce/request" | |
- | + | Iterface: "com.nokia.mce.request" | |
- | + | Member: "get_device_orientation" | |
- | + | </pre> | |
- | + | ||
- | + | ||
This method returns several values: | This method returns several values: | ||
- | * | + | * gchar * portrait/landscape orientation (see mce/mode-names.h for valid portrait/landscape states) |
- | * | + | * gchar * on/off stand (see mce/mode-names.h for valid stand states) |
- | * | + | * gchar * face up/face down (see mce/mode-names.h for valid facing states) |
- | * | + | * dbus_int32_t x axis (unit mG) |
- | * | + | * dbus_int32_t y axis (unit mG) |
- | * | + | * dbus_int32_t z axis (unit mG) |
- | In our case we are only interested in the first return value which will be 'portrait' or 'landscape'. Because we only need to know the first value here we can use the < | + | In our case we are only interested in the first return value which will be 'portrait' or 'landscape'. Because we only need to know the first value here we can use the <tt>osso_rpc_run_system()</tt> function for making this call to DBus. It's a convenience function provided by libosso for making DBus calls. The advantage is that our code gets shorter, the disadvantage is that it only return the first return value - which in our case is ok. So here is the code using libosso. |
- | < | + | <pre> |
#include <mce/dbus-names.h> | #include <mce/dbus-names.h> | ||
#include <mce-dev/mode-names.h | #include <mce-dev/mode-names.h | ||
Line 346: | Line 332: | ||
return result; | return result; | ||
} | } | ||
- | </ | + | </pre> |
- | + | === Listening To Hardware Orientation Changes === | |
So now you know how to ask the device for its orientation. Now let's see how to connect a signal handler to listen to changes in the orientation. | So now you know how to ask the device for its orientation. Now let's see how to connect a signal handler to listen to changes in the orientation. | ||
First here is again the signature: | First here is again the signature: | ||
- | + | <pre> | |
- | + | Service: "com.nokia.mce" | |
- | + | Path: "/com/nokia/mce/signal" | |
- | + | Iterface: "com.nokia.mce.signal" | |
- | + | Member: "sig_device_orientation_ind" | |
- | + | </pre> | |
- | + | ||
- | + | ||
- | + | ||
The signal transports three values: | The signal transports three values: | ||
- | * | + | * gchar * portrait/landscape orientation (see mce/mode-names.h for valid portrait/landscape states) |
- | * | + | * gchar * on/off stand (see mce/mode-names.h for valid stand states) |
- | * | + | * gchar * face up/face down (see mce/mode-names.h for valid facing states) |
- | Again we are only interested in the first value which is 'portrait' or 'landscape'. Unfortunately there is no libosso convenience function for listening to | + | Again we are only interested in the first value which is 'portrait' or 'landscape'. Unfortunately there is no libosso convenience function for listening to DBus signals, so we have to use the raw DBus API. |
- | < | + | <pre> |
static DBusHandlerResult | static DBusHandlerResult | ||
dbus_handle_mce_message(DBusConnection *con, DBusMessage *msg, gpointer data) | dbus_handle_mce_message(DBusConnection *con, DBusMessage *msg, gpointer data) | ||
Line 385: | Line 368: | ||
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; | return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; | ||
} | } | ||
- | </ | + | </pre> |
Now we need to register this signal handler. | Now we need to register this signal handler. | ||
- | < | + | <pre> |
#define MCE_MATCH_RULE "type='signal',interface='" MCE_SIGNAL_IF "',member='" MCE_DEVICE_ORIENTATION_SIG "'" | #define MCE_MATCH_RULE "type='signal',interface='" MCE_SIGNAL_IF "',member='" MCE_DEVICE_ORIENTATION_SIG "'" | ||
Line 398: | Line 381: | ||
dbus_bus_add_match(con, MCE_MATCH_RULE, NULL); | dbus_bus_add_match(con, MCE_MATCH_RULE, NULL); | ||
dbus_connection_add_filter(con, dbus_handle_mce_message, NULL, NULL); | dbus_connection_add_filter(con, dbus_handle_mce_message, NULL, NULL); | ||
- | </ | + | </pre> |
- | + | === Listening To Hardware Orientation Changes (Python example) === | |
- | This short snippet should get you started (you only need the | + | This short snippet should get you started (you only need the gobject.MainLoop if you are writing a console application). "handler" will be called every time the orientation changes, and the first parameter is the important one (compare it to "landscape" and "portrait"). |
- | < | + | <pre>import dbus |
- | import dbus | + | |
import dbus.glib | import dbus.glib | ||
Line 429: | Line 411: | ||
# Start the main loop - only needed for console apps | # Start the main loop - only needed for console apps | ||
- | mainloop.run() | + | mainloop.run()</pre> |
- | </ | + | |
- | + | == Testing Hardware Orientation In Scratchbox == | |
- | + | Testing whether or not your DBus signal handler for device orientation change works is easy. Just run the following commands inside scratchbox while your application is running. | |
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | Testing whether or not your | + | |
Device was rotated into portrait mode: | Device was rotated into portrait mode: | ||
Line 494: | Line 431: | ||
<pre>mce --debug-mode</pre> | <pre>mce --debug-mode</pre> | ||
- | Now the | + | Now the DBus call to the MCE should return 'landscape'. It probably will always return 'landscape' when run inside the SDK as it is not possible to really rotated the "device" there. |
- | + | ||
- | + | ||
+ | = References = | ||
In no particular order | In no particular order | ||
* http://maemo.org/api_refs/5.0/beta/tutorial/html | * http://maemo.org/api_refs/5.0/beta/tutorial/html | ||
* http://maemo.org/api_refs/5.0/beta/hig/html | * http://maemo.org/api_refs/5.0/beta/hig/html | ||
+ | |||
* http://lists.maemo.org/pipermail//maemo-developers/2009-May/019368.html | * http://lists.maemo.org/pipermail//maemo-developers/2009-May/019368.html | ||
* http://lists.maemo.org/pipermail//maemo-developers/2009-May/019144.html | * http://lists.maemo.org/pipermail//maemo-developers/2009-May/019144.html | ||
Line 507: | Line 444: | ||
* http://lists.maemo.org/pipermail//maemo-developers/2009-June/019579.html | * http://lists.maemo.org/pipermail//maemo-developers/2009-June/019579.html | ||
* http://lists.maemo.org/pipermail//maemo-developers/2009-August/020202.html | * http://lists.maemo.org/pipermail//maemo-developers/2009-August/020202.html | ||
+ | |||
* https://bugs.maemo.org/show_bug.cgi?id=4617 | * https://bugs.maemo.org/show_bug.cgi?id=4617 | ||
* https://bugs.maemo.org/show_bug.cgi?id=4618 | * https://bugs.maemo.org/show_bug.cgi?id=4618 |
Learn more about Contributing to the wiki.