diff options
author | Ted Gould <ted@gould.cx> | 2010-08-09 09:43:20 -0500 |
---|---|---|
committer | Ted Gould <ted@gould.cx> | 2010-08-09 09:43:20 -0500 |
commit | afac3d90213157ecb77cc2395de3d710d5d2f60d (patch) | |
tree | 7092a74a4654a3776695ec38806807b88d332462 /src | |
parent | 9291697e3e6d4270a7f6200c0dc3d85743feb6d2 (diff) | |
parent | 89186858938bec991dfcbe931764b291edd24917 (diff) | |
download | libayatana-appindicator-afac3d90213157ecb77cc2395de3d710d5d2f60d.tar.gz libayatana-appindicator-afac3d90213157ecb77cc2395de3d710d5d2f60d.tar.bz2 libayatana-appindicator-afac3d90213157ecb77cc2395de3d710d5d2f60d.zip |
Start with the ABI break.
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 5 | ||||
-rw-r--r-- | src/app-indicator.c | 218 | ||||
-rw-r--r-- | src/app-indicator.h | 37 | ||||
-rw-r--r-- | src/application-service-marshal.list | 1 | ||||
-rw-r--r-- | src/dbus-properties-client.h | 139 | ||||
-rw-r--r-- | src/notification-item.xml | 6 |
6 files changed, 260 insertions, 146 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 68be1c0..0e84749 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -94,10 +94,11 @@ BUILT_SOURCES += \ libappindicator_la_SOURCES = \ $(libappindicator_headers) \ app-indicator-enum-types.c \ - app-indicator.c + app-indicator.c \ + application-service-marshal.c libappindicator_la_LDFLAGS = \ - -version-info 0:0:0 \ + -version-info 1:0:0 \ -no-undefined \ -export-symbols-regex "^[^_d].*" diff --git a/src/app-indicator.c b/src/app-indicator.c index fdfcc23..22b9c03 100644 --- a/src/app-indicator.c +++ b/src/app-indicator.c @@ -37,6 +37,7 @@ License version 3 and version 2.1 along with this program. If not, see #include "app-indicator.h" #include "app-indicator-enum-types.h" +#include "application-service-marshal.h" #include "notification-item-server.h" #include "notification-watcher-client.h" @@ -72,6 +73,9 @@ struct _AppIndicatorPrivate { gchar *icon_theme_path; DbusmenuServer *menuservice; GtkWidget *menu; + gchar * label; + gchar * label_guide; + guint label_change_idle; GtkStatusIcon * status_icon; gint fallback_timer; @@ -87,6 +91,7 @@ enum { NEW_ICON, NEW_ATTENTION_ICON, NEW_STATUS, + NEW_LABEL, CONNECTION_CHANGED, NEW_ICON_THEME_PATH, LAST_SIGNAL @@ -105,7 +110,9 @@ enum { PROP_ATTENTION_ICON_NAME, PROP_ICON_THEME_PATH, PROP_MENU, - PROP_CONNECTED + PROP_CONNECTED, + PROP_LABEL, + PROP_LABEL_GUIDE }; /* The strings so that they can be slowly looked up. */ @@ -117,6 +124,8 @@ enum { #define PROP_ICON_THEME_PATH_S "icon-theme-path" #define PROP_MENU_S "menu" #define PROP_CONNECTED_S "connected" +#define PROP_LABEL_S "label" +#define PROP_LABEL_GUIDE_S "label-guide" /* Private macro, shhhh! */ #define APP_INDICATOR_GET_PRIVATE(o) \ @@ -137,6 +146,7 @@ static void app_indicator_finalize (GObject *object); static void app_indicator_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); static void app_indicator_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); /* Other stuff */ +static void signal_label_change (AppIndicator * self); static void check_connect (AppIndicator * self); static void register_service_cb (DBusGProxy * proxy, GError * error, gpointer data); static void start_fallback_timer (AppIndicator * self, gboolean disable_timeout); @@ -285,6 +295,41 @@ app_indicator_class_init (AppIndicatorClass *klass) "Pretty simple, true if we have a reasonable expectation of being displayed through this object. You should hide your TrayIcon if so.", FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + /** + AppIndicator:label: + + A label that can be shown next to the string in the application + indicator. The label will not be shown unless there is an icon + as well. The label is useful for numerical and other frequently + updated information. In general, it shouldn't be shown unless a + user requests it as it can take up a significant amount of space + on the user's panel. This may not be shown in all visualizations. + */ + g_object_class_install_property(object_class, + PROP_LABEL, + g_param_spec_string (PROP_LABEL_S, + "A label next to the icon", + "A label to provide dynamic information.", + NULL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + AppIndicator:label-guide: + + An optional string to provide guidance to the panel on how big + the #AppIndicator:label string could get. If this is set correctly + then the panel should never 'jiggle' as the string adjusts through + out the range of options. For instance, if you were providing a + percentage like "54% thrust" in #AppIndicator:label you'd want to + set this string to "100% thrust" to ensure space when Scotty can + get you enough power. + */ + g_object_class_install_property(object_class, + PROP_LABEL_GUIDE, + g_param_spec_string (PROP_LABEL_GUIDE_S, + "A string to size the space available for the label.", + "To ensure that the label does not cause the panel to 'jiggle' this string should provide information on how much space it could take.", + NULL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /* Signals */ @@ -334,6 +379,23 @@ app_indicator_class_init (AppIndicatorClass *klass) G_TYPE_STRING); /** + AppIndicator::new-label: + @arg0: The #AppIndicator object + @arg1: The string for the label + @arg1: The string for the guide + + Emitted when either #AppIndicator:label or #AppIndicator:label-guide are + changed. + */ + signals[NEW_LABEL] = g_signal_new (APP_INDICATOR_SIGNAL_NEW_LABEL, + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (AppIndicatorClass, new_label), + NULL, NULL, + _application_service_marshal_VOID__STRING_STRING, + G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING); + + /** AppIndicator::connection-changed: @arg0: The #AppIndicator object @arg1: Whether we're connected or not @@ -384,6 +446,9 @@ app_indicator_init (AppIndicator *self) priv->icon_theme_path = NULL; priv->menu = NULL; priv->menuservice = NULL; + priv->label = NULL; + priv->label_guide = NULL; + priv->label_change_idle = 0; priv->watcher_proxy = NULL; priv->connection = NULL; @@ -435,6 +500,11 @@ app_indicator_dispose (GObject *object) priv->fallback_timer = 0; } + if (priv->label_change_idle != 0) { + g_source_remove(priv->label_change_idle); + priv->label_change_idle = 0; + } + if (priv->menu != NULL) { g_signal_handlers_disconnect_by_func (G_OBJECT (priv->menu), client_menu_changed, @@ -507,6 +577,16 @@ app_indicator_finalize (GObject *object) g_free(priv->icon_theme_path); priv->icon_theme_path = NULL; } + + if (priv->label != NULL) { + g_free(priv->label); + priv->label = NULL; + } + + if (priv->label_guide != NULL) { + g_free(priv->label_guide); + priv->label_guide = NULL; + } G_OBJECT_CLASS (app_indicator_parent_class)->finalize (object); return; @@ -578,6 +658,43 @@ app_indicator_set_property (GObject * object, guint prop_id, const GValue * valu check_connect (self); break; + case PROP_LABEL: { + gchar * oldlabel = priv->label; + priv->label = g_value_dup_string(value); + + if (g_strcmp0(oldlabel, priv->label) != 0) { + signal_label_change(APP_INDICATOR(object)); + } + + if (priv->label != NULL && priv->label[0] == '\0') { + g_free(priv->label); + priv->label = NULL; + } + + if (oldlabel != NULL) { + g_free(oldlabel); + } + break; + } + case PROP_LABEL_GUIDE: { + gchar * oldguide = priv->label_guide; + priv->label_guide = g_value_dup_string(value); + + if (g_strcmp0(oldguide, priv->label_guide) != 0) { + signal_label_change(APP_INDICATOR(object)); + } + + if (priv->label_guide != NULL && priv->label_guide[0] == '\0') { + g_free(priv->label_guide); + priv->label_guide = NULL; + } + + if (oldguide != NULL) { + g_free(oldguide); + } + break; + } + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -635,6 +752,14 @@ app_indicator_get_property (GObject * object, guint prop_id, GValue * value, GPa g_value_set_boolean (value, priv->watcher_proxy != NULL ? TRUE : FALSE); break; + case PROP_LABEL: + g_value_set_string (value, priv->label); + break; + + case PROP_LABEL_GUIDE: + g_value_set_string (value, priv->label_guide); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -643,6 +768,39 @@ app_indicator_get_property (GObject * object, guint prop_id, GValue * value, GPa return; } +/* Sends the label changed signal and resets the source ID */ +static gboolean +signal_label_change_idle (gpointer user_data) +{ + AppIndicator * self = (AppIndicator *)user_data; + AppIndicatorPrivate *priv = self->priv; + + g_signal_emit(G_OBJECT(self), signals[NEW_LABEL], 0, + priv->label != NULL ? priv->label : "", + priv->label_guide != NULL ? priv->label_guide : "", + TRUE); + + priv->label_change_idle = 0; + + return FALSE; +} + +/* Sets up an idle function to send the label changed signal + so that we don't send it too many times. */ +static void +signal_label_change (AppIndicator * self) +{ + AppIndicatorPrivate *priv = self->priv; + + /* don't set it twice */ + if (priv->label_change_idle != 0) { + return; + } + + priv->label_change_idle = g_idle_add(signal_label_change_idle, self); + return; +} + /* This function is used to see if we have enough information to connect to things. If we do, and we're not connected, it connects for us. */ @@ -1150,6 +1308,31 @@ app_indicator_set_icon (AppIndicator *self, const gchar *icon_name) } /** + app_indicator_set_label: + @self: The #AppIndicator object to use + @label: The label to show next to the icon. + @guide: A guide to size the label correctly. + + This is a wrapper function for the #AppIndicator:label and + #AppIndicator:guide properties. This function can take #NULL + as either @label or @guide and will clear the entries. +*/ +void +app_indicator_set_label (AppIndicator *self, const gchar * label, const gchar * guide) +{ + g_return_if_fail (IS_APP_INDICATOR (self)); + /* Note: The label can be NULL, it's okay */ + /* Note: The guide can be NULL, it's okay */ + + g_object_set(G_OBJECT(self), + PROP_LABEL_S, label == NULL ? "" : label, + PROP_LABEL_GUIDE_S, guide == NULL ? "" : guide, + NULL); + + return; +} + +/** app_indicator_set_icon_theme_path: @self: The #AppIndicator object to use @icon_theme_path: The icon theme path to set. @@ -1717,3 +1900,36 @@ app_indicator_get_menu (AppIndicator *self) return GTK_MENU(priv->menu); } + +/** + app_indicator_get_label: + @self: The #AppIndicator object to use + + Wrapper function for property #AppIndicator:label. + + Return value: The current label. +*/ +const gchar * +app_indicator_get_label (AppIndicator *self) +{ + g_return_val_if_fail (IS_APP_INDICATOR (self), NULL); + + return self->priv->label; +} + +/** + app_indicator_get_label_guide: + @self: The #AppIndicator object to use + + Wrapper function for property #AppIndicator:label-guide. + + Return value: The current label guide. +*/ +const gchar * +app_indicator_get_label_guide (AppIndicator *self) +{ + g_return_val_if_fail (IS_APP_INDICATOR (self), NULL); + + return self->priv->label_guide; +} + diff --git a/src/app-indicator.h b/src/app-indicator.h index b17f023..a9e1c38 100644 --- a/src/app-indicator.h +++ b/src/app-indicator.h @@ -93,6 +93,11 @@ G_BEGIN_DECLS String identifier for the #AppIndicator::new-status signal. */ /** + APP_INDICATOR_SIGNAL_NEW_LABEL: + + String identifier for the #AppIndicator::new-label signal. +*/ +/** APP_INDICATOR_SIGNAL_CONNECTION_CHANGED: String identifier for the #AppIndicator::connection-changed signal. @@ -105,6 +110,7 @@ G_BEGIN_DECLS #define APP_INDICATOR_SIGNAL_NEW_ICON "new-icon" #define APP_INDICATOR_SIGNAL_NEW_ATTENTION_ICON "new-attention-icon" #define APP_INDICATOR_SIGNAL_NEW_STATUS "new-status" +#define APP_INDICATOR_SIGNAL_NEW_LABEL "new-label" #define APP_INDICATOR_SIGNAL_CONNECTION_CHANGED "connection-changed" #define APP_INDICATOR_SIGNAL_NEW_ICON_THEME_PATH "new-icon-theme-path" @@ -155,12 +161,20 @@ typedef struct _AppIndicatorPrivate AppIndicatorPrivate; @new_attention_icon: Slot for #AppIndicator::new-attention-icon. @new_status: Slot for #AppIndicator::new-status. @new_icon_theme_path: Slot for #AppIndicator::new-icon-theme-path + @new_label: Slot for #AppIndicator::new-label. @connection_changed: Slot for #AppIndicator::connection-changed. + @app_indicator_reserved_sw: Reserved for future use. + @app_indicator_reserved_ats: Reserved for future use. @fallback: Function that gets called to make a #GtkStatusIcon when there is no Application Indicator area available. @unfallback: The function that gets called if an Application Indicator area appears after the fallback has been created. + @app_indicator_reserved_1: Reserved for future use. @app_indicator_reserved_2: Reserved for future use. + @app_indicator_reserved_3: Reserved for future use. + @app_indicator_reserved_4: Reserved for future use. + @app_indicator_reserved_5: Reserved for future use. + @app_indicator_reserved_6: Reserved for future use. The signals and external functions that make up the #AppIndicator class object. @@ -177,23 +191,33 @@ struct _AppIndicatorClass { void (* new_status) (AppIndicator *indicator, const gchar *status, gpointer user_data); + void (* new_icon_theme_path) (AppIndicator *indicator, + const gchar *icon_theme_path, + gpointer user_data); + void (* new_label) (AppIndicator *indicator, + const gchar *label, + const gchar *guide, + gpointer user_data); /* Local Signals */ void (* connection_changed) (AppIndicator * indicator, gboolean connected, gpointer user_data); + void (*app_indicator_reserved_sw)(void); + void (*app_indicator_reserved_ats)(void); /* Overridable Functions */ GtkStatusIcon * (*fallback) (AppIndicator * indicator); void (*unfallback) (AppIndicator * indicator, GtkStatusIcon * status_icon); - void (* new_icon_theme_path) (AppIndicator *indicator, - const gchar *icon_theme_path, - gpointer user_data); - /* Reserved */ + void (*app_indicator_reserved_1)(void); void (*app_indicator_reserved_2)(void); + void (*app_indicator_reserved_3)(void); + void (*app_indicator_reserved_4)(void); + void (*app_indicator_reserved_5)(void); + void (*app_indicator_reserved_6)(void); }; /** @@ -236,6 +260,9 @@ void app_indicator_set_menu (AppIndicator GtkMenu *menu); void app_indicator_set_icon (AppIndicator *self, const gchar *icon_name); +void app_indicator_set_label (AppIndicator *self, + const gchar *label, + const gchar *guide); void app_indicator_set_icon_theme_path(AppIndicator *self, const gchar *icon_theme_path); @@ -247,6 +274,8 @@ const gchar * app_indicator_get_icon (AppIndicator * const gchar * app_indicator_get_icon_theme_path(AppIndicator *self); const gchar * app_indicator_get_attention_icon (AppIndicator *self); GtkMenu * app_indicator_get_menu (AppIndicator *self); +const gchar * app_indicator_get_label (AppIndicator *self); +const gchar * app_indicator_get_label_guide (AppIndicator *self); G_END_DECLS diff --git a/src/application-service-marshal.list b/src/application-service-marshal.list index 4ac8398..b49ff41 100644 --- a/src/application-service-marshal.list +++ b/src/application-service-marshal.list @@ -18,3 +18,4 @@ # with this program. If not, see <http://www.gnu.org/licenses/>. VOID: STRING, INT, STRING, STRING, STRING VOID: INT, STRING +VOID: STRING, STRING diff --git a/src/dbus-properties-client.h b/src/dbus-properties-client.h deleted file mode 100644 index 6f08e78..0000000 --- a/src/dbus-properties-client.h +++ /dev/null @@ -1,139 +0,0 @@ -/* Generated by dbus-binding-tool; do not edit! */ - -#include <glib.h> -#include <dbus/dbus-glib.h> - -G_BEGIN_DECLS - -#ifndef _DBUS_GLIB_ASYNC_DATA_FREE -#define _DBUS_GLIB_ASYNC_DATA_FREE -static -#ifdef G_HAVE_INLINE -inline -#endif -void -_dbus_glib_async_data_free (gpointer stuff) -{ - g_slice_free (DBusGAsyncData, stuff); -} -#endif - -#ifndef DBUS_GLIB_CLIENT_WRAPPERS_org_freedesktop_DBus_Properties -#define DBUS_GLIB_CLIENT_WRAPPERS_org_freedesktop_DBus_Properties - -static -#ifdef G_HAVE_INLINE -inline -#endif -gboolean -org_freedesktop_DBus_Properties_get (DBusGProxy *proxy, const char * IN_Interface_Name, const char * IN_Property_Name, GValue* OUT_Value, GError **error) - -{ - return dbus_g_proxy_call (proxy, "Get", error, G_TYPE_STRING, IN_Interface_Name, G_TYPE_STRING, IN_Property_Name, G_TYPE_INVALID, G_TYPE_VALUE, OUT_Value, G_TYPE_INVALID); -} - -typedef void (*org_freedesktop_DBus_Properties_get_reply) (DBusGProxy *proxy, GValue OUT_Value, GError *error, gpointer userdata); - -static void -org_freedesktop_DBus_Properties_get_async_callback (DBusGProxy *proxy, DBusGProxyCall *call, void *user_data) -{ - DBusGAsyncData *data = (DBusGAsyncData*) user_data; - GError *error = NULL; - GValue OUT_Value = { 0, }; - dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_VALUE, &OUT_Value, G_TYPE_INVALID); - (*(org_freedesktop_DBus_Properties_get_reply)data->cb) (proxy, OUT_Value, error, data->userdata); - return; -} - -static -#ifdef G_HAVE_INLINE -inline -#endif -DBusGProxyCall* -org_freedesktop_DBus_Properties_get_async (DBusGProxy *proxy, const char * IN_Interface_Name, const char * IN_Property_Name, org_freedesktop_DBus_Properties_get_reply callback, gpointer userdata) - -{ - DBusGAsyncData *stuff; - stuff = g_slice_new (DBusGAsyncData); - stuff->cb = G_CALLBACK (callback); - stuff->userdata = userdata; - return dbus_g_proxy_begin_call (proxy, "Get", org_freedesktop_DBus_Properties_get_async_callback, stuff, _dbus_glib_async_data_free, G_TYPE_STRING, IN_Interface_Name, G_TYPE_STRING, IN_Property_Name, G_TYPE_INVALID); -} -static -#ifdef G_HAVE_INLINE -inline -#endif -gboolean -org_freedesktop_DBus_Properties_set (DBusGProxy *proxy, const char * IN_Interface_Name, const char * IN_Property_Name, const GValue* IN_Value, GError **error) - -{ - return dbus_g_proxy_call (proxy, "Set", error, G_TYPE_STRING, IN_Interface_Name, G_TYPE_STRING, IN_Property_Name, G_TYPE_VALUE, IN_Value, G_TYPE_INVALID, G_TYPE_INVALID); -} - -typedef void (*org_freedesktop_DBus_Properties_set_reply) (DBusGProxy *proxy, GError *error, gpointer userdata); - -static void -org_freedesktop_DBus_Properties_set_async_callback (DBusGProxy *proxy, DBusGProxyCall *call, void *user_data) -{ - DBusGAsyncData *data = (DBusGAsyncData*) user_data; - GError *error = NULL; - dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INVALID); - (*(org_freedesktop_DBus_Properties_set_reply)data->cb) (proxy, error, data->userdata); - return; -} - -static -#ifdef G_HAVE_INLINE -inline -#endif -DBusGProxyCall* -org_freedesktop_DBus_Properties_set_async (DBusGProxy *proxy, const char * IN_Interface_Name, const char * IN_Property_Name, const GValue* IN_Value, org_freedesktop_DBus_Properties_set_reply callback, gpointer userdata) - -{ - DBusGAsyncData *stuff; - stuff = g_slice_new (DBusGAsyncData); - stuff->cb = G_CALLBACK (callback); - stuff->userdata = userdata; - return dbus_g_proxy_begin_call (proxy, "Set", org_freedesktop_DBus_Properties_set_async_callback, stuff, _dbus_glib_async_data_free, G_TYPE_STRING, IN_Interface_Name, G_TYPE_STRING, IN_Property_Name, G_TYPE_VALUE, IN_Value, G_TYPE_INVALID); -} -static -#ifdef G_HAVE_INLINE -inline -#endif -gboolean -org_freedesktop_DBus_Properties_get_all (DBusGProxy *proxy, const char * IN_Interface_Name, GHashTable** OUT_Properties, GError **error) - -{ - return dbus_g_proxy_call (proxy, "GetAll", error, G_TYPE_STRING, IN_Interface_Name, G_TYPE_INVALID, dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE), OUT_Properties, G_TYPE_INVALID); -} - -typedef void (*org_freedesktop_DBus_Properties_get_all_reply) (DBusGProxy *proxy, GHashTable *OUT_Properties, GError *error, gpointer userdata); - -static void -org_freedesktop_DBus_Properties_get_all_async_callback (DBusGProxy *proxy, DBusGProxyCall *call, void *user_data) -{ - DBusGAsyncData *data = (DBusGAsyncData*) user_data; - GError *error = NULL; - GHashTable* OUT_Properties; - dbus_g_proxy_end_call (proxy, call, &error, dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE), &OUT_Properties, G_TYPE_INVALID); - (*(org_freedesktop_DBus_Properties_get_all_reply)data->cb) (proxy, OUT_Properties, error, data->userdata); - return; -} - -static -#ifdef G_HAVE_INLINE -inline -#endif -DBusGProxyCall* -org_freedesktop_DBus_Properties_get_all_async (DBusGProxy *proxy, const char * IN_Interface_Name, org_freedesktop_DBus_Properties_get_all_reply callback, gpointer userdata) - -{ - DBusGAsyncData *stuff; - stuff = g_slice_new (DBusGAsyncData); - stuff->cb = G_CALLBACK (callback); - stuff->userdata = userdata; - return dbus_g_proxy_begin_call (proxy, "GetAll", org_freedesktop_DBus_Properties_get_all_async_callback, stuff, _dbus_glib_async_data_free, G_TYPE_STRING, IN_Interface_Name, G_TYPE_INVALID); -} -#endif /* defined DBUS_GLIB_CLIENT_WRAPPERS_org_freedesktop_DBus_Properties */ - -G_END_DECLS diff --git a/src/notification-item.xml b/src/notification-item.xml index dc755c9..01261b5 100644 --- a/src/notification-item.xml +++ b/src/notification-item.xml @@ -12,6 +12,8 @@ to find the icons specified above. --> <property name="IconThemePath" type="s" access="read" /> <property name="Menu" type="o" access="read" /> + <property name="Label" type="s" access="read" /> + <property name="LabelGuide" type="s" access="read" /> <!-- Methods --> <!-- None currently --> @@ -27,6 +29,10 @@ <signal name="NewStatus"> <arg type="s" name="status" direction="out" /> </signal> + <signal name="NewLabel"> + <arg type="s" name="label" direction="out" /> + <arg type="s" name="guide" direction="out" /> + </signal> </interface> </node> |