vglang.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561
  1. /*
  2. * CDE - Common Desktop Environment
  3. *
  4. * Copyright (c) 1993-2012, The Open Group. All rights reserved.
  5. *
  6. * These libraries and programs are free software; you can
  7. * redistribute them and/or modify them under the terms of the GNU
  8. * Lesser General Public License as published by the Free Software
  9. * Foundation; either version 2 of the License, or (at your option)
  10. * any later version.
  11. *
  12. * These libraries and programs are distributed in the hope that
  13. * they will be useful, but WITHOUT ANY WARRANTY; without even the
  14. * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  15. * PURPOSE. See the GNU Lesser General Public License for more
  16. * details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with these libraries and programs; if not, write
  20. * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
  21. * Floor, Boston, MA 02110-1301 USA
  22. */
  23. /* $TOG: vglang.c /main/7 1998/03/04 19:28:18 mgreess $ */
  24. /* *
  25. * (c) Copyright 1993, 1994 Hewlett-Packard Company *
  26. * (c) Copyright 1993, 1994 International Business Machines Corp. *
  27. * (c) Copyright 1993, 1994 Sun Microsystems, Inc. *
  28. * (c) Copyright 1993, 1994 Novell, Inc. *
  29. */
  30. /****************************************************************************
  31. **
  32. ** File: ui.c
  33. **
  34. ** Project: Common Desktop Environment
  35. **
  36. ** Description: common ui code for login manager
  37. **
  38. **
  39. ****************************************************************************
  40. ************************************<+>*************************************/
  41. /***************************************************************************
  42. *
  43. * Includes
  44. *
  45. ***************************************************************************/
  46. #include <stdio.h>
  47. #include "vg.h"
  48. #include "vgmsg.h"
  49. #include <Xm/CascadeBG.h>
  50. #include <Xm/RowColumn.h>
  51. #include <Xm/ToggleBG.h>
  52. /***************************************************************************
  53. *
  54. * GetLangName
  55. *
  56. * Convert an actual locale name to a meaningful language name which will
  57. * be shown in the language menu. This function may be platform dependent.
  58. ***************************************************************************/
  59. static char *
  60. GetLangName( char *label )
  61. {
  62. /*
  63. * Default implementation is to use langName resource. Language names can be
  64. * set in Dtlogin file as follows. (In this case, en_US is a locale name which
  65. * can be set to LANG environment variable.
  66. *
  67. * Dtlogin*en_US*languageName: English (ISO8859-1)
  68. */
  69. char rmname[50];
  70. char rmclass[50];
  71. char *rmtype;
  72. XrmValue rmvalue;
  73. sprintf(rmname, "Dtlogin*%s*languageName", label);
  74. sprintf(rmclass, "Dtlogin*%s*LanguageName", label);
  75. if(XrmGetResource(XtDatabase(dpyinfo.dpy), rmname, rmclass, &rmtype,
  76. &rmvalue)) {
  77. return(rmvalue.addr);
  78. }
  79. else
  80. return(NULL);
  81. }
  82. #if defined (ENABLE_DYNAMIC_LANGLIST)
  83. /***************************************************************************
  84. *
  85. * Methods for dynamic language list
  86. *
  87. ***************************************************************************/
  88. /*
  89. * _enumLangCmdStart() - start enumeration of languages and descriptions
  90. *
  91. * The command specified by Dtlogin*languageListCmd command returns
  92. * the list of locales and a translated description of each.
  93. */
  94. static void *
  95. _enumLangCmdStart(void)
  96. {
  97. if (appInfo.languageListCmd)
  98. {
  99. return((void *)popen(appInfo.languageListCmd, "r"));
  100. }
  101. return(NULL);
  102. }
  103. /*
  104. * _enumLangCmdNext() - get next language description pair
  105. * note: *lang and *desc must be freed by free()
  106. *
  107. * Read the next locale and description from pipe. Default description
  108. * comes from system, but user may override with Xresources description.
  109. */
  110. static Boolean
  111. _enumLangCmdNext(
  112. void *state,
  113. char **lang,
  114. char **desc)
  115. {
  116. char buf[200];
  117. Boolean rc = False;
  118. if (fgets(buf, sizeof(buf), (FILE *)state) != NULL)
  119. {
  120. /*
  121. * The buf format is "locale desc ...\n". For example:
  122. *
  123. * pl_PL Polish ISO8859-2
  124. * pt_BR Portuguese (Brazil) ISO8859-1
  125. */
  126. char *loclang = strtok(buf, " "); /* lang name from system */
  127. char *locdesc = strtok(NULL, "\n"); /* description from system */
  128. char *userdesc; /* user provided description from Xresources */
  129. if ((userdesc = GetLangName(loclang)) != NULL)
  130. {
  131. locdesc = userdesc; /* use user provided description */
  132. }
  133. *lang = strdup(loclang);
  134. *desc = strdup(locdesc);
  135. rc = True;
  136. }
  137. return(rc);
  138. }
  139. /*
  140. * _enumLangCmdEnd() - end enumeration of language names and descriptions
  141. *
  142. * Close pipe.
  143. */
  144. static void
  145. _enumLangCmdEnd(
  146. void *state)
  147. {
  148. pclose((FILE *)state);
  149. }
  150. #endif /* ENABLE_DYNAMIC_LANGLIST */
  151. /***************************************************************************
  152. *
  153. * Methods for language list of type 'LANGLIST'
  154. *
  155. ***************************************************************************/
  156. #define DELIM " \t" /* delimiters in language list */
  157. struct _enumState
  158. {
  159. char *dupstr;
  160. char *tokstr;
  161. };
  162. /*
  163. * _enumLanglistStart() - start enumeration of languages and descriptions
  164. *
  165. * Dtlogin sets up the LANGLIST env var which contains the list
  166. * of locale names to display in the language menus.
  167. */
  168. static void *
  169. _enumLanglistStart(void)
  170. {
  171. char *p;
  172. struct _enumState *state = malloc(sizeof(struct _enumState));
  173. if (state)
  174. {
  175. if ((p = (char *)getenv(LANGLIST)) == NULL )
  176. {
  177. free(state);
  178. state = NULL;
  179. }
  180. else
  181. {
  182. state->dupstr = strdup(p);
  183. state->tokstr = state->dupstr;
  184. }
  185. }
  186. return((void *)state);
  187. }
  188. /*
  189. * _enumLanglistNext() - get next language description pair
  190. * note: *lang and *desc must be freed by free()
  191. *
  192. * Get next locale from LANGLIST and get possible description from
  193. * Xresources.
  194. */
  195. static Boolean
  196. _enumLanglistNext(
  197. void *state,
  198. char **lang,
  199. char **desc)
  200. {
  201. Boolean rc = False;
  202. struct _enumState *enumstate = (struct _enumState *)state;
  203. char *loclang, *locdesc;
  204. loclang = strtok(enumstate->tokstr, DELIM);
  205. if (enumstate->tokstr)
  206. {
  207. enumstate->tokstr = NULL;
  208. }
  209. if (loclang != NULL)
  210. {
  211. if ((locdesc = GetLangName(loclang)) == NULL)
  212. {
  213. locdesc = loclang;
  214. }
  215. *lang = strdup(loclang);
  216. *desc = strdup(locdesc);
  217. rc = True;
  218. }
  219. return(rc);
  220. }
  221. /*
  222. * _enumLanglistEnd() - end enumeration of language names and descriptions
  223. *
  224. * Free memory.
  225. */
  226. static void
  227. _enumLanglistEnd(
  228. void *state)
  229. {
  230. struct _enumState *enumstate = (struct _enumState *)state;
  231. free(enumstate->dupstr);
  232. free((char *)state);
  233. }
  234. /***************************************************************************
  235. *
  236. * Methods for language list
  237. *
  238. ***************************************************************************/
  239. struct _enumObject
  240. {
  241. Boolean (*methodNext)();
  242. void (*methodEnd)();
  243. void *enumstate;
  244. };
  245. /*
  246. * _enumLangStart() - start enumeration of languages and descriptions
  247. *
  248. * ENABLE_DYNAMIC_LANGLIST defined
  249. * Enumerate LANGLIST. If unsucessful, try 'LangCmd'. LANGLIST will only
  250. * be set if user specified Dtlogin*languageList.
  251. *
  252. * ENABLE_DYNAMIC_LANGLIST undefined
  253. * Enumerate LANGLIST.
  254. *
  255. */
  256. static void *
  257. _enumLangStart(void)
  258. {
  259. char *p;
  260. struct _enumObject *state = malloc(sizeof(struct _enumObject));
  261. if (state)
  262. {
  263. state->enumstate = _enumLanglistStart();
  264. if (state->enumstate != NULL)
  265. {
  266. state->methodNext = _enumLanglistNext;
  267. state->methodEnd = _enumLanglistEnd;
  268. }
  269. #if defined (ENABLE_DYNAMIC_LANGLIST)
  270. if (state->enumstate == NULL)
  271. {
  272. state->enumstate = _enumLangCmdStart();
  273. if (state->enumstate != NULL)
  274. {
  275. state->methodNext = _enumLangCmdNext;
  276. state->methodEnd = _enumLangCmdEnd;
  277. }
  278. }
  279. #endif /* ENABLE_DYNAMIC_LANGLIST */
  280. if (state->enumstate == NULL)
  281. {
  282. free(state);
  283. state = NULL;
  284. }
  285. }
  286. return((void *)state);
  287. }
  288. /*
  289. * _enumLangNext() - get next language description pair
  290. * note: *lang and *desc must be freed by free()
  291. */
  292. static Boolean
  293. _enumLangNext(
  294. void *state,
  295. char **lang,
  296. char **desc)
  297. {
  298. Boolean rc;
  299. struct _enumObject *object = (struct _enumObject *)state;
  300. rc = (*object->methodNext)(object->enumstate, lang, desc);
  301. return(rc);
  302. }
  303. /*
  304. * _enumLangEnd() - end enumeration of language names and descriptions
  305. */
  306. static void
  307. _enumLangEnd(
  308. void *state)
  309. {
  310. struct _enumObject *object = (struct _enumObject *)state;
  311. (*object->methodEnd)(object->enumstate);
  312. free((char *)state);
  313. }
  314. /***************************************************************************
  315. *
  316. * MakeLangMenu
  317. *
  318. * Widgets: lang_menu
  319. *
  320. * The language menu contains the list of locales available to the
  321. * the desktop session. This may be a subset of the actual installed
  322. * locales. The list of locales to display in the language menu can
  323. * be provided by the sysadmin, or determined by the login manager.
  324. *
  325. * * Sysadmin provided language list
  326. *
  327. * A sysadmin can set the Dtlogin.languageList resource to set the list
  328. * of languages. The dtlogin process provides this list to dtgreet
  329. * in the LANGLIST environment variable. This has priority.
  330. *
  331. * * Login manager determined language list
  332. *
  333. * If the sysadm does not set Dtlogin.languageList, ie. LANGLIST unset,
  334. * the login manager will generate the list. There are two methods for
  335. * doing this, one of which is selected at compile time with the
  336. * ENABLE_DYNAMIC_LANGLIST define.
  337. *
  338. * * dynamic list (ENABLE_DYNAMIC_LANGLIST defined)
  339. *
  340. * This method executes the command specified by the
  341. * Dtlogin*languageListCmd resource. The default is
  342. * /usr/dt/bin/dtlslocale. The languageListCmd command is expected
  343. * to write to stdout a series of language names and descriptions:
  344. *
  345. * lang_name description
  346. * lang_name description
  347. * ...
  348. *
  349. * Example:
  350. *
  351. * En_US English (United States) - IBM-850
  352. * Fr_BE French (Belgium) - IBM-850
  353. *
  354. * Also, since languageListCmd is run under dtgreet's locale, a
  355. * localized description can be returned.
  356. *
  357. * * static list (ENABLE_DYNAMIC_LANGLIST undefined)
  358. *
  359. * This method has dtlogin querying the system and generating
  360. * the language list to be provided to dtgreet via the LANGLIST
  361. * environment variable. In this case dtlogin takes care to use the
  362. * sysadmin provided list if necessary.
  363. *
  364. * * Language descriptions
  365. *
  366. * The sysadmin can set the Dtlogin*<lang>.languageName resource to
  367. * provide a descriptive name for a particular language. If languageName
  368. * unset, the value used depends on ENABLE_DYNAMIC_LANGLIST. If
  369. * ENABLE_DYNAMIC_LANGLIST set, the value used is the descriptive text
  370. * provided by languageListCmd. If ENABLE_DYNAMIC_LANGLIST unset, the value
  371. * used is simply the locale name.
  372. *
  373. * * Default language
  374. *
  375. * The sysadmin can set the Dtlogin*language resource to specify the
  376. * default language in the language menu.
  377. *
  378. ***************************************************************************/
  379. #define MAX_LANG_ITEMS 16 /* maximum number of items in one lang menu */
  380. #define MAX_NAME_LEN 128 /* maximum length of a language name */
  381. struct Langlist {
  382. char *lang; /* lang name ie En_US, Ja_JP */
  383. char *desc; /* lang description ie English */
  384. };
  385. /*
  386. * compareLangDesc() - compare language descriptions in qsort()
  387. */
  388. static int
  389. compareLangDesc(
  390. const void *first,
  391. const void *second)
  392. {
  393. return(strcmp(((struct Langlist *)first)->desc,
  394. ((struct Langlist *)second)->desc));
  395. }
  396. void
  397. MakeLangMenu( void )
  398. {
  399. int i, k;
  400. char cblab[MAX_NAME_LEN]; /* pushbutton label */
  401. int nlang; /* total number of languages */
  402. int nlangMenus; /* number of language sub-menus */
  403. int maxitems; /* max no. of items in sub-lang menu*/
  404. Widget item_menu;
  405. Widget button;
  406. char *tostr;
  407. struct Langlist {
  408. char *lang; /* lang name ie En_US, Ja_JP */
  409. char *desc; /* lang description ie English */
  410. };
  411. struct Langlist list[500];
  412. void *state;
  413. /*
  414. * Generate list of langname/description pairs.
  415. */
  416. nlang = 0;
  417. state = _enumLangStart();
  418. if (state)
  419. {
  420. while (_enumLangNext(state, &list[nlang].lang, &list[nlang].desc))
  421. {
  422. nlang++;
  423. }
  424. _enumLangEnd(state);
  425. }
  426. if (nlang > 0) {
  427. /*
  428. * Sort by description
  429. */
  430. qsort((char *)list, nlang, sizeof(list[0]), compareLangDesc);
  431. /*
  432. * determine number of language sub-menus ...
  433. * (MAX_LANG_ITEMS per menu)
  434. */
  435. nlangMenus = 0;
  436. do {
  437. nlangMenus++;
  438. maxitems = nlang/nlangMenus;
  439. } while ( maxitems > MAX_LANG_ITEMS );
  440. if (nlang%nlangMenus != 0) maxitems++; /* allow for stragglers */
  441. /*
  442. * build language menu(s)...
  443. */
  444. i = 0;
  445. lang_menu = XmCreatePulldownMenu(options_menu, "lang_menu", argt, i);
  446. item_menu = lang_menu;
  447. for (k = 0; k < nlang; k++) {
  448. if ( nlangMenus > 1 && k%maxitems == 0) {
  449. i = 0;
  450. item_menu = XmCreatePulldownMenu(lang_menu, "item_menu",
  451. argt, i);
  452. }
  453. /*
  454. * build toggle buttons...
  455. */
  456. i = InitArg(ToggleBG);
  457. XtSetArg(argt[i], XmNrecomputeSize, True ); i++;
  458. if (langenv && (strcmp(langenv, list[k].lang) == 0)) {
  459. XtSetArg(argt[i], XmNset, True ); i++;
  460. }
  461. xmstr = XmStringCreateLocalized(list[k].desc);
  462. XtSetArg(argt[i], XmNlabelString, xmstr ); i++;
  463. button = XmCreateToggleButtonGadget(
  464. item_menu, list[k].lang, argt, i);
  465. XtAddCallback (button, XmNvalueChangedCallback,
  466. RespondLangCB, (XtPointer) list[k].lang);
  467. XmStringFree(xmstr);
  468. XtManageChild(button);
  469. tostr =
  470. (char*) ReadCatalog(MC_LABEL_SET, MC_TO_LABEL, MC_DEF_TO_LABEL);
  471. if ( nlangMenus > 1 && k%maxitems == 0 ) {
  472. int first = k;
  473. int last = k+maxitems >= nlang ? nlang-1 : k+maxitems-1;
  474. i = InitArg(CascadeBG);
  475. sprintf(cblab, "%s %s %s",
  476. list[first].desc, tostr, list[last].desc);
  477. xmstr = XmStringCreateLocalized(cblab);
  478. XtSetArg(argt[i], XmNlabelString, xmstr ); i++;
  479. XtSetArg(argt[i], XmNsubMenuId, item_menu ); i++;
  480. XtSetArg(argt[i], XmNrecomputeSize, True ); i++;
  481. button = XmCreateCascadeButtonGadget(lang_menu, cblab, argt, i);
  482. XtManageChild(button);
  483. XmStringFree(xmstr);
  484. }
  485. }
  486. /*
  487. * Free language list
  488. */
  489. for (k = 0; k < nlang; k++)
  490. {
  491. /* free(list[k].lang); -- used as callback data, don't free */
  492. free(list[k].desc);
  493. }
  494. }
  495. }