diff options
Diffstat (limited to 'obt')
| -rw-r--r-- | obt/bsearch.h | 3 | ||||
| -rw-r--r-- | obt/keyboard.c | 3 | ||||
| -rw-r--r-- | obt/prop.c | 339 | ||||
| -rw-r--r-- | obt/prop.h | 77 | ||||
| -rwxr-xr-x | obt/tests/bstest.c | 58 | ||||
| -rwxr-xr-x | obt/tests/ddtest.c | 61 | ||||
| -rw-r--r-- | obt/tests/ddtest.desktop | 15 | ||||
| -rwxr-xr-x[-rw-r--r--] | obt/tests/linktest.c (renamed from obt/watch.h) | 45 | ||||
| -rwxr-xr-x | obt/tests/watchtest.c | 50 | ||||
| -rw-r--r-- | obt/watch.c | 233 | ||||
| -rw-r--r-- | obt/xml.c | 3 |
11 files changed, 479 insertions, 408 deletions
diff --git a/obt/bsearch.h b/obt/bsearch.h index 65e42680..9613c51b 100644 --- a/obt/bsearch.h +++ b/obt/bsearch.h @@ -40,8 +40,9 @@ G_BEGIN_DECLS if ((val) == (ar)[out_BSEARCH]) { \ break; \ } \ - else if ((val) < (ar)[out_BSEARCH]) \ + else if ((val) < (ar)[out_BSEARCH] && out_BSEARCH > 0) { \ r_BSEARCH = out_BSEARCH-1; /* search to the left side */ \ + } \ else \ l_BSEARCH = out_BSEARCH+1; /* search to the left side */ \ } \ diff --git a/obt/keyboard.c b/obt/keyboard.c index db327a6b..8bfdd39b 100644 --- a/obt/keyboard.c +++ b/obt/keyboard.c @@ -439,7 +439,8 @@ void obt_keyboard_context_unref(ObtIC *ic) { if (--ic->ref < 1) { xic_all = g_slist_remove(xic_all, ic); - XDestroyIC(ic->xic); + if (ic->xic) + XDestroyIC(ic->xic); g_slice_free(ObtIC, ic); } } @@ -45,7 +45,8 @@ void obt_prop_startup(void) CREATE(PIXMAP); CREATE(ATOM); CREATE(STRING); - CREATE_NAME(UTF8, "UTF8_STRING"); + CREATE(COMPOUND_TEXT); + CREATE(UTF8_STRING); CREATE(MANAGER); @@ -283,128 +284,236 @@ static gboolean get_all(Window win, Atom prop, Atom type, gint size, return ret; } -static gboolean get_stringlist(Window win, Atom prop, gchar ***list, gint *nstr) +/*! Get a text property from a window, and fill out the XTextProperty with it. + @param win The window to read the property from. + @param prop The atom of the property to read off the window. + @param tprop The XTextProperty to fill out. + @param type 0 to get text of any type, or a value from + ObtPropTextType to restrict the value to a specific type. + @return TRUE if the text was read and validated against the @type, and FALSE + otherwise. +*/ +static gboolean get_text_property(Window win, Atom prop, + XTextProperty *tprop, ObtPropTextType type) { - XTextProperty tprop; - gboolean ret = FALSE; - - if (XGetTextProperty(obt_display, win, &tprop, prop) && tprop.nitems) { - if (XTextPropertyToStringList(&tprop, list, nstr)) - ret = TRUE; - XFree(tprop.value); + if (!(XGetTextProperty(obt_display, win, tprop, prop) && tprop->nitems)) + return FALSE; + if (!type) + return TRUE; /* no type checking */ + switch (type) { + case OBT_PROP_TEXT_STRING: + case OBT_PROP_TEXT_STRING_XPCS: + case OBT_PROP_TEXT_STRING_NO_CC: + return tprop->encoding == OBT_PROP_ATOM(STRING); + case OBT_PROP_TEXT_COMPOUND_TEXT: + return tprop->encoding == OBT_PROP_ATOM(COMPOUND_TEXT); + case OBT_PROP_TEXT_UTF8_STRING: + return tprop->encoding == OBT_PROP_ATOM(UTF8_STRING); + default: + g_assert_not_reached(); } - return ret; -} - -gboolean obt_prop_get32(Window win, Atom prop, Atom type, guint32 *ret) -{ - return get_prealloc(win, prop, type, 32, (guchar*)ret, 1); } -gboolean obt_prop_get_array32(Window win, Atom prop, Atom type, guint32 **ret, - guint *nret) +/*! Returns one or more UTF-8 encoded strings from the text property. + @param tprop The XTextProperty to convert into UTF-8 string(s). + @param type The type which specifies the format that the text must meet, or + 0 to allow any valid characters that can be converted to UTF-8 through. + @param max The maximum number of strings to return. -1 to return them all. + @return If max is 1, then this returns a gchar* with the single string. + Otherwise, this returns a gchar** of no more than max strings (or all + strings read, if max is negative). If an error occurs, NULL is returned. + */ +static void* convert_text_property(XTextProperty *tprop, + ObtPropTextType type, gint max) { - return get_all(win, prop, type, 32, (guchar**)ret, nret); -} - -gboolean obt_prop_get_string_locale(Window win, Atom prop, gchar **ret) -{ - gchar **list; - gint nstr; - gchar *s; - - if (get_stringlist(win, prop, &list, &nstr) && nstr) { - s = g_locale_to_utf8(list[0], -1, NULL, NULL, NULL); - XFreeStringList(list); - if (s) { - *ret = s; - return TRUE; + enum { + LATIN1, + UTF8, + LOCALE + } encoding; + const gboolean return_single = (max == 1); + gboolean ok = FALSE; + gchar **strlist = NULL; + gchar *single[1] = { NULL }; + gchar **retlist = single; /* single is used when max == 1 */ + gint i, n_strs; + + /* Read each string in the text property and store a pointer to it in + retlist. These pointers point into the X data structures directly. + + Then we will convert them to UTF-8, and replace the retlist pointer with + a new one. + */ + if (tprop->encoding == OBT_PROP_ATOM(COMPOUND_TEXT)) + { + encoding = LOCALE; + ok = (XmbTextPropertyToTextList( + obt_display, tprop, &strlist, &n_strs) == Success); + if (ok) { + if (max >= 0) + n_strs = MIN(max, n_strs); + if (!return_single) + retlist = g_new0(gchar*, n_strs+1); + if (retlist) + for (i = 0; i < n_strs; ++i) + retlist[i] = strlist[i]; } } - return FALSE; -} - -gboolean obt_prop_get_strings_locale(Window win, Atom prop, gchar ***ret) -{ - GSList *strs = NULL, *it; - gchar *raw, *p; - guint num, i, count = 0; - - if (get_all(win, prop, OBT_PROP_ATOM(STRING), 8, - (guchar**)&raw, &num)) + else if (tprop->encoding == OBT_PROP_ATOM(UTF8_STRING) || + tprop->encoding == OBT_PROP_ATOM(STRING)) { - p = raw; - while (p < raw + num) { - ++count; - strs = g_slist_append(strs, p); + gchar *p; /* iterator */ + + if (tprop->encoding == OBT_PROP_ATOM(STRING)) + encoding = LATIN1; + else + encoding = UTF8; + ok = TRUE; + + /* First, count the number of strings. Then make a structure for them + and copy pointers to them into it. */ + p = (gchar*)tprop->value; + n_strs = 0; + while (p < (gchar*)tprop->value + tprop->nitems) { p += strlen(p) + 1; /* next string */ + ++n_strs; } - *ret = g_new0(gchar*, count + 1); - (*ret)[count] = NULL; /* null terminated list */ + if (max >= 0) + n_strs = MIN(max, n_strs); + if (!return_single) + retlist = g_new0(gchar*, n_strs+1); + if (retlist) { + p = (gchar*)tprop->value; + for (i = 0; i < n_strs; ++i) { + retlist[i] = p; + p += strlen(p) + 1; /* next string */ + } + } + } + + if (!(ok && retlist)) { + if (strlist) XFreeStringList(strlist); + return NULL; + } + + /* convert each element in retlist to UTF-8, and replace it. */ + for (i = 0; i < n_strs; ++i) { + if (encoding == UTF8) { + const gchar *end; /* the first byte past the valid data */ - for (i = 0, it = strs; it; ++i, it = g_slist_next(it)) { - (*ret)[i] = g_locale_to_utf8(it->data, -1, NULL, NULL, NULL); - /* make sure translation did not fail */ - if (!(*ret)[i]) - (*ret)[i] = g_strdup(""); + g_utf8_validate(retlist[i], -1, &end); + retlist[i] = g_strndup(retlist[i], end-retlist[i]); + } + else if (encoding == LOCALE) { + gsize nvalid; /* the number of valid bytes at the front of the + string */ + gchar *utf; /* the string converted into utf8 */ + + utf = g_locale_to_utf8(retlist[i], -1, &nvalid, NULL, NULL); + if (!utf) + utf = g_locale_to_utf8(retlist[i], nvalid, NULL, NULL, NULL); + g_assert(utf); + retlist[i] = utf; + } + else { /* encoding == LATIN1 */ + gsize nvalid; /* the number of valid bytes at the front of the + string */ + gchar *utf; /* the string converted into utf8 */ + gchar *p; /* iterator */ + + /* look for invalid characters */ + for (p = retlist[i], nvalid = 0; *p; ++p, ++nvalid) { + /* The only valid control characters are TAB(HT)=9 and + NEWLINE(LF)=10. + This is defined in ICCCM section 2: + http://tronche.com/gui/x/icccm/sec-2.html. + See a definition of the latin1 codepage here: + http://en.wikipedia.org/wiki/ISO/IEC_8859-1. + The above page includes control characters in the table, + which we must explicitly exclude, as the g_convert function + will happily take them. + */ + const register guchar c = (guchar)*p; /* unsigned value at p */ + if ((c < 32 && c != 9 && c != 10) || (c >= 127 && c <= 160)) + break; /* found a control character that isn't allowed */ + + if (type == OBT_PROP_TEXT_STRING_NO_CC && c < 32) + break; /* absolutely no control characters are allowed */ + + if (type == OBT_PROP_TEXT_STRING_XPCS) { + const gboolean valid = ( + (c >= 32 && c < 128) || c == 9 || c == 10); + if (!valid) + break; /* strict whitelisting for XPCS */ + } + } + /* look for invalid latin1 characters */ + utf = g_convert(retlist[i], nvalid, "utf-8", "iso-8859-1", + &nvalid, NULL, NULL); + if (!utf) + utf = g_convert(retlist[i], nvalid, "utf-8", "iso-8859-1", + NULL, NULL, NULL); + g_assert(utf); + retlist[i] = utf; } - g_free(raw); - g_slist_free(strs); - return TRUE; } - return FALSE; + + if (strlist) XFreeStringList(strlist); + if (return_single) + return retlist[0]; + else + return retlist; } -gboolean obt_prop_get_string_utf8(Window win, Atom prop, gchar **ret) +gboolean obt_prop_get32(Window win, Atom prop, Atom type, guint32 *ret) { - gchar *raw; + return get_prealloc(win, prop, type, 32, (guchar*)ret, 1); +} + +gboolean obt_prop_get_array32(Window win, Atom prop, Atom type, guint32 **ret, + guint *nret) +{ + return get_all(win, prop, type, 32, (guchar**)ret, nret); +} + +gboolean obt_prop_get_text(Window win, Atom prop, ObtPropTextType type, + gchar **ret_string) +{ + XTextProperty tprop; gchar *str; - guint num; + gboolean ret = FALSE; - if (get_all(win, prop, OBT_PROP_ATOM(UTF8), 8, - (guchar**)&raw, &num)) - { - str = g_strndup(raw, num); /* grab the first string from the list */ - g_free(raw); - if (g_utf8_validate(str, -1, NULL)) { - *ret = str; - return TRUE; + if (get_text_property(win, prop, &tprop, type)) { + str = (gchar*)convert_text_property(&tprop, type, 1); + + if (str) { + *ret_string = str; + ret = TRUE; } - g_free(str); } - return FALSE; + XFree(tprop.value); + return ret; } -gboolean obt_prop_get_strings_utf8(Window win, Atom prop, gchar ***ret) +gboolean obt_prop_get_array_text(Window win, Atom prop, + ObtPropTextType type, + gchar ***ret_strings) { - GSList *strs = NULL, *it; - gchar *raw, *p; - guint num, i, count = 0; - - if (get_all(win, prop, OBT_PROP_ATOM(UTF8), 8, - (guchar**)&raw, &num)) - { - p = raw; - while (p < raw + num) { - ++count; - strs = g_slist_append(strs, p); - p += strlen(p) + 1; /* next string */ - } + XTextProperty tprop; + gchar **strs; + gboolean ret = FALSE; - *ret = g_new0(gchar*, count + 1); + if (get_text_property(win, prop, &tprop, type)) { + strs = (gchar**)convert_text_property(&tprop, type, -1); - for (i = 0, it = strs; it; ++i, it = g_slist_next(it)) { - if (g_utf8_validate(it->data, -1, NULL)) - (*ret)[i] = g_strdup(it->data); - else - (*ret)[i] = g_strdup(""); + if (strs) { + *ret_strings = strs; + ret = TRUE; } - g_free(raw); - g_slist_free(strs); - return TRUE; } - return FALSE; + XFree(tprop.value); + return ret; } void obt_prop_set32(Window win, Atom prop, Atom type, gulong val) @@ -420,45 +529,13 @@ void obt_prop_set_array32(Window win, Atom prop, Atom type, gulong *val, (guchar*)val, num); } -void obt_prop_set_string_locale(Window win, Atom prop, const gchar *val) -{ - gchar const *s[2] = { val, NULL }; - obt_prop_set_strings_locale(win, prop, s); -} - -void obt_prop_set_strings_locale(Window win, Atom prop, - const gchar *const *strs) -{ - gint i, count; - gchar **lstrs; - XTextProperty tprop; - - /* count the strings in strs, and convert them to the locale format */ - for (count = 0; strs[count]; ++count); - lstrs = g_new0(char*, count); - for (i = 0; i < count; ++i) { - lstrs[i] = g_locale_from_utf8(strs[i], -1, NULL, NULL, NULL); - if (!lstrs[i]) { - lstrs[i] = g_strdup(""); /* make it an empty string */ - g_warning("Unable to translate string '%s' from UTF8 to locale " - "format", strs[i]); - } - } - - - XStringListToTextProperty(lstrs, count, &tprop); - XSetTextProperty(obt_display, win, &tprop, prop); - XFree(tprop.value); -} - -void obt_prop_set_string_utf8(Window win, Atom prop, const gchar *val) +void obt_prop_set_text(Window win, Atom prop, const gchar *val) { - XChangeProperty(obt_display, win, prop, OBT_PROP_ATOM(UTF8), 8, + XChangeProperty(obt_display, win, prop, OBT_PROP_ATOM(UTF8_STRING), 8, PropModeReplace, (const guchar*)val, strlen(val)); } -void obt_prop_set_strings_utf8(Window win, Atom prop, - const gchar *const *strs) +void obt_prop_set_array_text(Window win, Atom prop, const gchar *const *strs) { GString *str; gchar const *const *s; @@ -468,7 +545,7 @@ void obt_prop_set_strings_utf8(Window win, Atom prop, str = g_string_append(str, *s); str = g_string_append_c(str, '\0'); } - XChangeProperty(obt_display, win, prop, obt_prop_atom(OBT_PROP_UTF8), 8, + XChangeProperty(obt_display, win, prop, OBT_PROP_ATOM(UTF8_STRING), 8, PropModeReplace, (guchar*)str->str, str->len); g_string_free(str, TRUE); } @@ -28,11 +28,13 @@ G_BEGIN_DECLS typedef enum { /* types */ OBT_PROP_CARDINAL, /*!< The atom which represents the Cardinal data type */ - OBT_PROP_WINDOW, /*!< The atom which represents window ids */ - OBT_PROP_PIXMAP, /*!< The atom which represents pixmap ids */ - OBT_PROP_ATOM, /*!< The atom which represents atom values */ - OBT_PROP_STRING, /*!< The atom which represents ascii strings */ - OBT_PROP_UTF8, /*!< The atom which represents utf8-encoded strings */ + OBT_PROP_WINDOW, /*!< The atom which represents window ids */ + OBT_PROP_PIXMAP, /*!< The atom which represents pixmap ids */ + OBT_PROP_ATOM, /*!< The atom which represents atom values */ + OBT_PROP_STRING, /*!< The atom which represents latin1 strings */ + OBT_PROP_COMPOUND_TEXT, /*!< The atom which represents locale-encoded + strings */ + OBT_PROP_UTF8_STRING, /*!< The atom which represents utf8-encoded strings*/ /* selection stuff */ OBT_PROP_MANAGER, @@ -223,23 +225,39 @@ typedef enum { Atom obt_prop_atom(ObtPropAtom a); +typedef enum { + /*! STRING is latin1 encoded. It cannot contain control characters except + for tab and line-feed. */ + OBT_PROP_TEXT_STRING = 1, + /*! STRING text restricted to characters in the X Portable Character + Set, which is a subset of latin1. + http://static.cray-cyber.org/Documentation/NEC_SX_R10_1/G1AE02E/CHAP1.HTML + */ + OBT_PROP_TEXT_STRING_XPCS = 2, + /*! STRING text restricted to not allow any control characters to be + present. */ + OBT_PROP_TEXT_STRING_NO_CC = 3, + /* COMPOUND_TEXT is encoded in the current locale setting. */ + OBT_PROP_TEXT_COMPOUND_TEXT = 4, + /* UTF8_STRING is encoded as utf-8. */ + OBT_PROP_TEXT_UTF8_STRING = 5, +} ObtPropTextType; + gboolean obt_prop_get32(Window win, Atom prop, Atom type, guint32 *ret); gboolean obt_prop_get_array32(Window win, Atom prop, Atom type, guint32 **ret, guint *nret); -gboolean obt_prop_get_string_locale(Window win, Atom prop, gchar **ret); -gboolean obt_prop_get_string_utf8(Window win, Atom prop, gchar **ret); -gboolean obt_prop_get_strings_locale(Window win, Atom prop, gchar ***ret); -gboolean obt_prop_get_strings_utf8(Window win, Atom prop, gchar ***ret); + +gboolean obt_prop_get_text(Window win, Atom prop, ObtPropTextType type, + gchar **ret); +gboolean obt_prop_get_array_text(Window win, Atom prop, + ObtPropTextType type, + gchar ***ret); void obt_prop_set32(Window win, Atom prop, Atom type, gulong val); void obt_prop_set_array32(Window win, Atom prop, Atom type, gulong *val, guint num); -void obt_prop_set_string_locale(Window win, Atom prop, const gchar *val); -void obt_prop_set_string_utf8(Window win, Atom prop, const gchar *val); -void obt_prop_set_strings_locale(Window win, Atom prop, - const gchar *const *strs); -void obt_prop_set_strings_utf8(Window win, Atom prop, - const gchar *const *strs); +void obt_prop_set_text(Window win, Atom prop, const gchar *str); +void obt_prop_set_array_text(Window win, Atom prop, const gchar *const *strs); void obt_prop_erase(Window win, Atom prop); @@ -257,20 +275,33 @@ void obt_prop_message_to(Window to, Window about, Atom messagetype, #define OBT_PROP_GETA32(win, prop, type, ret, nret) \ (obt_prop_get_array32(win, OBT_PROP_ATOM(prop), OBT_PROP_ATOM(type), \ ret, nret)) -#define OBT_PROP_GETS(win, prop, type, ret) \ - (obt_prop_get_string_##type(win, OBT_PROP_ATOM(prop), ret)) -#define OBT_PROP_GETSS(win, prop, type, ret) \ - (obt_prop_get_strings_##type(win, OBT_PROP_ATOM(prop), ret)) +#define OBT_PROP_GETS(win, prop, ret) \ + (obt_prop_get_text(win, OBT_PROP_ATOM(prop), 0, ret)) +#define OBT_PROP_GETSS(win, prop, ret) \ + (obt_prop_get_array_text(win, OBT_PROP_ATOM(prop), 0, ret)) + +#define OBT_PROP_GETS_TYPE(win, prop, type, ret) \ + (obt_prop_get_text(win, OBT_PROP_ATOM(prop), OBT_PROP_TEXT_##type, ret)) +#define OBT_PROP_GETSS_TYPE(win, prop, type, ret) \ + (obt_prop_get_array_text(win, OBT_PROP_ATOM(prop), \ + OBT_PROP_TEXT_##type, ret)) + +#define OBT_PROP_GETS_UTF8(win, prop, ret) \ + OBT_PROP_GETS_TYPE(win, prop, UTF8_STRING, ret) +#define OBT_PROP_GETSS_UTF8(win, prop, ret) \ + OBT_PROP_GETSS_TYPE(win, prop, UTF8_STRING, ret) +#define OBT_PROP_GETS_XPCS(win, prop, ret) \ + OBT_PROP_GETS_TYPE(win, prop, STRING_XPCS, ret) #define OBT_PROP_SET32(win, prop, type, val) \ (obt_prop_set32(win, OBT_PROP_ATOM(prop), OBT_PROP_ATOM(type), val)) #define OBT_PROP_SETA32(win, prop, type, val, num) \ (obt_prop_set_array32(win, OBT_PROP_ATOM(prop), OBT_PROP_ATOM(type), \ val, num)) -#define OBT_PROP_SETS(win, prop, type, val) \ - (obt_prop_set_string_##type(win, OBT_PROP_ATOM(prop), val)) -#define OBT_PROP_SETSS(win, prop, type, strs) \ - (obt_prop_set_strings_##type(win, OBT_PROP_ATOM(prop), strs)) +#define OBT_PROP_SETS(win, prop, val) \ + (obt_prop_set_text(win, OBT_PROP_ATOM(prop), val)) +#define OBT_PROP_SETSS(win, prop, strs) \ + (obt_prop_set_array_text(win, OBT_PROP_ATOM(prop), strs)) #define OBT_PROP_ERASE(win, prop) (obt_prop_erase(win, OBT_PROP_ATOM(prop))) diff --git a/obt/tests/bstest.c b/obt/tests/bstest.c new file mode 100755 index 00000000..75818551 --- /dev/null +++ b/obt/tests/bstest.c @@ -0,0 +1,58 @@ +#/* +#!/bin/sh +#*/ +#if 0 +gcc -O0 -o ./bstest `pkg-config --cflags --libs obt-3.5` bstest.c && \ +./bstest +exit +#endif + +/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*- + + bstest.c for the Openbox window manager + Copyright (c) 2010 Dana Jansens + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + See the COPYING file for a copy of the GNU General Public License. +*/ + +#include "../bsearch.h" +#include <stdio.h> + +int main() { + int ar[] = { + 2, 4, 5, 7, 12, 34, 45, 56, 57, 67, 67, 68, 68, 69, 70, 71, 89, 100 }; + int n = sizeof(ar)/sizeof(ar[0]); + BSEARCH_SETUP(int); + BSEARCH(int, ar, 0, n, 1); + g_assert(!!BSEARCH_FOUND() == FALSE); + BSEARCH(int, ar, 0, n, 0); + g_assert(!!BSEARCH_FOUND() == FALSE); + BSEARCH(int, ar, 0, n, 2); + g_assert(!!BSEARCH_FOUND() == TRUE); + g_assert(BSEARCH_AT() == 0); + BSEARCH(int, ar, 0, n, 58); + g_assert(!!BSEARCH_FOUND() == FALSE); + BSEARCH(int, ar, 0, n, 57); + g_assert(!!BSEARCH_FOUND() == TRUE); + g_assert(BSEARCH_AT() == 8); + BSEARCH(int, ar, 0, n, 55); + g_assert(!!BSEARCH_FOUND() == FALSE); + BSEARCH(int, ar, 0, n, 99); + g_assert(!!BSEARCH_FOUND() == FALSE); + BSEARCH(int, ar, 0, n, 100); + g_assert(!!BSEARCH_FOUND() == TRUE); + g_assert(BSEARCH_AT() == 17); + BSEARCH(int, ar, 0, n, 101); + g_assert(!!BSEARCH_FOUND() == FALSE); + g_print("ok\n"); +} diff --git a/obt/tests/ddtest.c b/obt/tests/ddtest.c new file mode 100755 index 00000000..69a9e1cf --- /dev/null +++ b/obt/tests/ddtest.c @@ -0,0 +1,61 @@ +#/* +#!/bin/sh +#*/ +#if 0 +gcc -O0 -o ./ddtest `pkg-config --cflags --libs obt-3.5` ddtest.c && \ +./ddtest +exit +#endif + +/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*- + + ddtest.c for the Openbox window manager + Copyright (c) 2010 Dana Jansens + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + See the COPYING file for a copy of the GNU General Public License. +*/ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include "obt/paths.h" +#include "obt/link.h" +#include <glib.h> + +gint main(int argc, char **argv) +{ + ObtPaths *obtpaths; + ObtLink *dd; + gchar *id; + + if (argc < 2) { + g_print("pass path to .desktop\n"); + return 1; + } + + obtpaths = obt_paths_new(); + dd = obt_link_from_ddfile(argv[1], obtpaths, "et", NULL, NULL); + obt_paths_unref(obtpaths); + if (dd) { + g_print("Success\n"); + { + gulong i, n; + const GQuark *c = obt_link_app_categories(dd, &n); + for (i = 0; i < n; ++i) + g_print("Category: %s\n", + g_quark_to_string(c[i])); + } + obt_link_unref(dd); + } + return 0; +} diff --git a/obt/tests/ddtest.desktop b/obt/tests/ddtest.desktop new file mode 100644 index 00000000..16d76aaa --- /dev/null +++ b/obt/tests/ddtest.desktop @@ -0,0 +1,15 @@ +[Desktop Entry] +test= +test2 +foo = +#hi +gewh= yuhself +a-r950 = tek;la; fi +hi=bye + +you=yeh +hi=double +Type=Application +Exec=foo +Name=myname +Categories=one;two;;three diff --git a/obt/watch.h b/obt/tests/linktest.c index c8556bc0..022ba35d 100644..100755 --- a/obt/watch.h +++ b/obt/tests/linktest.c @@ -1,6 +1,15 @@ +#/* +#!/bin/sh +#*/ +#if 0 +gcc -O0 -o ./linktest `pkg-config --cflags --libs obt-3.5` linktest.c && \ +./linktest +exit +#endif + /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*- - obt/watch.h for the Openbox window manager + linktest.c for the Openbox window manager Copyright (c) 2010 Dana Jansens This program is free software; you can redistribute it and/or modify @@ -16,26 +25,24 @@ See the COPYING file for a copy of the GNU General Public License. */ -#ifndef __obt_watch_h -#define __obt_watch_h - +#include "obt/linkbase.h" +#include "obt/paths.h" #include <glib.h> +#include <locale.h> -G_BEGIN_DECLS - -typedef struct _ObtWatch ObtWatch; +gint main() +{ + ObtLinkBase *base; + ObtPaths *paths; + GMainLoop *loop; -struct _ObtMainLoop; + paths = obt_paths_new(); + base = obt_linkbase_new(paths, setlocale(LC_MESSAGES, "")); + printf("done\n"); + return 0; -typedef void (*ObtWatchFunc)(ObtWatch *w, gchar *subpath, gpointer data); + loop = g_main_loop_new(NULL, FALSE); + g_main_loop_run(loop); -ObtWatch* obt_watch_new(); -void obt_watch_ref(ObtWatch *w); -void obt_watch_unref(ObtWatch *w); - -void obt_watch_dir(ObtWatch *w, const gchar *path, - ObtWatchFunc func, gpointer data); - -G_END_DECLS - -#endif + return 0; +} diff --git a/obt/tests/watchtest.c b/obt/tests/watchtest.c new file mode 100755 index 00000000..9ebdbaee --- /dev/null +++ b/obt/tests/watchtest.c @@ -0,0 +1,50 @@ +#/* +#!/bin/sh +#*/ +#if 0 +gcc -O0 -o ./watchtest `pkg-config --cflags --libs obt-3.5` watchtest.c && \ +./watchtest +exit +#endif + +/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*- + + watchtest.c for the Openbox window manager + Copyright (c) 2010 Dana Jansens + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + See the COPYING file for a copy of the GNU General Public License. +*/ + +#include "obt/watch.h" +#include <glib.h> + +void func(ObtWatch *w, const gchar *base_path, + const gchar *subpath, ObtWatchNotifyType type, + gpointer data) +{ + g_print("base path: %s subpath: %s type=%d\n", base_path, subpath, type); +} + +gint main() +{ + ObtWatch *watch; + GMainLoop *loop; + + watch = obt_watch_new(); + obt_watch_add(watch, "/tmp/a", FALSE, func, NULL); + + loop = g_main_loop_new(NULL, FALSE); + g_main_loop_run(loop); + + return 0; +} diff --git a/obt/watch.c b/obt/watch.c deleted file mode 100644 index c2f6487d..00000000 --- a/obt/watch.c +++ /dev/null @@ -1,233 +0,0 @@ -/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*- - - obt/watch.c for the Openbox window manager - Copyright (c) 2010 Dana Jansens - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - See the COPYING file for a copy of the GNU General Public License. -*/ - -#include "obt/watch.h" - -#ifdef HAVE_SYS_INOTIFY_H -# include <sys/inotify.h> -#endif -#ifdef HAVE_UNISTD_H -# include <unistd.h> -#endif -#include <errno.h> - -struct _ObtWatch { - guint ref; - gint ino_fd; - guint ino_watch; - GHashTable *targets; - -#ifdef HAVE_SYS_INOTIFY_H - GHashTable *targets_by_wd; -#endif -}; - -typedef struct _ObtWatchTarget { - ObtWatch *w; - -#ifdef HAVE_SYS_INOTIFY_H - gint wd; -#endif - - gchar *path; - ObtWatchFunc func; - gpointer data; -} ObtWatchTarget; - -static void init_inot(ObtWatch *w); -static gboolean read_inot(GIOChannel *s, GIOCondition cond, gpointer data); -static gboolean add_inot(ObtWatch *w, ObtWatchTarget *t, const char *path, - gboolean dir); -static void rm_inot(ObtWatchTarget *t); -static ObtWatchTarget* target_new(ObtWatch *w, const gchar *path, - ObtWatchFunc func, gpointer data); -static void target_free(ObtWatchTarget *t); - -ObtWatch* obt_watch_new() -{ - ObtWatch *w; - - w = g_slice_new(ObtWatch); - w->ref = 1; - w->ino_fd = -1; - w->targets = g_hash_table_new_full(g_str_hash, g_str_equal, - NULL, (GDestroyNotify)target_free); -#ifdef HAVE_SYS_INOTIFY_H - w->targets_by_wd = g_hash_table_new(g_int_hash, g_int_equal); -#endif - - init_inot(w); - - return w; -} -void obt_watch_ref(ObtWatch *w) -{ - ++w->ref; -} - -void obt_watch_unref(ObtWatch *w) -{ - if (--w->ref < 1) { - if (w->ino_fd >= 0 && w->ino_watch) - g_source_remove(w->ino_watch); - - g_hash_table_destroy(w->targets); - g_hash_table_destroy(w->targets_by_wd); - - g_slice_free(ObtWatch, w); - } -} - -static void init_inot(ObtWatch *w) -{ -#ifdef HAVE_SYS_INOTIFY_H - if (w->ino_fd >= 0) return; - - w->ino_fd = inotify_init(); - if (w->ino_fd >= 0) { - GIOChannel *ch; - - ch = g_io_channel_unix_new(w->ino_fd); - w->ino_watch = g_io_add_watch(ch, G_IO_IN | G_IO_HUP | G_IO_ERR, - read_inot, w); - g_io_channel_unref(ch); - } -#endif -} - -static gboolean read_inot(GIOChannel *src, GIOCondition cond, gpointer data) -{ -#ifdef HAVE_SYS_INOTIFY_H - ObtWatch *w = data; - ObtWatchTarget *t; - struct inotify_event s; - gint len; - guint ilen; - char *name; - - /* read the event */ - for (ilen = 0; ilen < sizeof(s); ilen += len) { - len = read(w->ino_fd, ((char*)&s)+ilen, sizeof(s)-ilen); - if (len < 0 && errno != EINTR) return FALSE; /* error, don't repeat */ - if (!len) return TRUE; /* nothing there */ - } - - name = g_new(char, s.len); - - /* read the filename */ - for (ilen = 0; ilen < s.len; ilen += len) { - len = read(w->ino_fd, name+ilen, s.len-ilen); - if (len < 0 && errno != EINTR) return FALSE; /* error, don't repeat */ - if (!len) return TRUE; /* nothing there */ - } - - t = g_hash_table_lookup(w->targets, &s.wd); - if (t) t->func(w, name, t->data); - - g_free(name); -#endif - return TRUE; /* repeat */ -} - -static gboolean add_inot(ObtWatch *w, ObtWatchTarget *t, const char *path, - gboolean dir) -{ -#ifndef HAVE_SYS_INOTIFY_H - return FALSE; -#else - gint mask; - if (w->ino_fd < 0) return FALSE; - if (dir) mask = IN_MODIFY | IN_CREATE | IN_DELETE | IN_MOVE; - else g_assert_not_reached(); - t->wd = inotify_add_watch(w->ino_fd, path, mask); - return TRUE; -#endif -} - -static void rm_inot(ObtWatchTarget *t) -{ -#ifdef HAVE_SYS_INOTIFY_H - if (t->w->ino_fd < 0) return; - if (t->wd < 0) return; - inotify_rm_watch(t->w->ino_fd, t->wd); -#endif -} - -static ObtWatchTarget* target_new(ObtWatch *w, const gchar *path, - ObtWatchFunc func, gpointer data) -{ - ObtWatchTarget *t; - - t = g_slice_new0(ObtWatchTarget); - t->w = w; - t->wd = -1; - t->path = g_strdup(path); - t->func = func; - t->data = data; - - if (!add_inot(w, t, path, TRUE)) { - g_assert_not_reached(); /* XXX do something */ - } - -#ifndef HAVE_SYS_INOTIFY_H -#error need inotify for now -#endif - - return t; -} - -static void target_free(ObtWatchTarget *t) -{ - rm_inot(t); - - g_free(t->path); - g_slice_free(ObtWatchTarget, t); -} - -void obt_paths_watch_dir(ObtWatch *w, const gchar *path, - ObtWatchFunc func, gpointer data) -{ - ObtWatchTarget *t; - - g_return_if_fail(w != NULL); - g_return_if_fail(path != NULL); - g_return_if_fail(data != NULL); - - t = target_new(w, path, func, data); - g_hash_table_insert(w->targets, t->path, t); -#ifdef HAVE_SYS_INOTIFY_H - g_hash_table_insert(w->targets_by_wd, &t->wd, t); -#endif -} - -void obt_paths_unwatch_dir(ObtWatch *w, const gchar *path) -{ - ObtWatchTarget *t; - - g_return_if_fail(w != NULL); - g_return_if_fail(path != NULL); - - t = g_hash_table_lookup(w->targets, path); - - if (t) { -#ifdef HAVE_SYS_INOTIFY_H - g_hash_table_remove(w->targets_by_wd, &t->wd); -#endif - g_hash_table_remove(w->targets, path); - } -} @@ -19,6 +19,7 @@ #include "obt/xml.h" #include "obt/paths.h" +#include <libxml/xinclude.h> #include <glib.h> #ifdef HAVE_STDLIB_H @@ -136,6 +137,8 @@ static gboolean load_file(ObtXmlInst *i, with extra nodes in it. */ i->doc = xmlReadFile(path, NULL, (XML_PARSE_NOBLANKS | XML_PARSE_RECOVER)); + xmlXIncludeProcessFlags(i->doc, (XML_PARSE_NOBLANKS | + XML_PARSE_RECOVER)); if (i->doc) { i->root = xmlDocGetRootElement(i->doc); if (!i->root) { |
