2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
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)
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
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
23 /* $TOG: vglang.c /main/7 1998/03/04 19:28:18 mgreess $ */
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. *
31 /****************************************************************************
35 ** Project: Common Desktop Environment
37 ** Description: common ui code for login manager
40 ****************************************************************************
41 ************************************<+>*************************************/
45 /***************************************************************************
49 ***************************************************************************/
54 #include <Xm/CascadeBG.h>
55 #include <Xm/RowColumn.h>
56 #include <Xm/ToggleBG.h>
58 /***************************************************************************
62 * Convert an actual locale name to a meaningful language name which will
63 * be shown in the language menu. This function may be platform dependent.
64 ***************************************************************************/
67 GetLangName( char *label )
70 * Default implementation is to use langName resource. Language names can be
71 * set in Dtlogin file as follows. (In this case, en_US is a locale name which
72 * can be set to LANG environment variable.
74 * Dtlogin*en_US*languageName: English (ISO8859-1)
81 sprintf(rmname, "Dtlogin*%s*languageName", label);
82 sprintf(rmclass, "Dtlogin*%s*LanguageName", label);
83 if(XrmGetResource(XtDatabase(dpyinfo.dpy), rmname, rmclass, &rmtype,
91 #if defined (ENABLE_DYNAMIC_LANGLIST)
92 /***************************************************************************
94 * Methods for dynamic language list
96 ***************************************************************************/
99 * _enumLangCmdStart() - start enumeration of languages and descriptions
101 * The command specified by Dtlogin*languageListCmd command returns
102 * the list of locales and a translated description of each.
105 _enumLangCmdStart(void)
107 if (appInfo.languageListCmd)
109 return((void *)popen(appInfo.languageListCmd, "r"));
115 * _enumLangCmdNext() - get next language description pair
116 * note: *lang and *desc must be freed by free()
118 * Read the next locale and description from pipe. Default description
119 * comes from system, but user may override with Xresources description.
130 if (fgets(buf, sizeof(buf), (FILE *)state) != NULL)
133 * The buf format is "locale desc ...\n". For example:
135 * pl_PL Polish ISO8859-2
136 * pt_BR Portuguese (Brazil) ISO8859-1
138 char *loclang = strtok(buf, " "); /* lang name from system */
139 char *locdesc = strtok(NULL, "\n"); /* description from system */
140 char *userdesc; /* user provided description from Xresources */
142 if ((userdesc = GetLangName(loclang)) != NULL)
144 locdesc = userdesc; /* use user provided description */
147 *lang = strdup(loclang);
148 *desc = strdup(locdesc);
155 * _enumLangCmdEnd() - end enumeration of language names and descriptions
163 pclose((FILE *)state);
165 #endif /* ENABLE_DYNAMIC_LANGLIST */
167 /***************************************************************************
169 * Methods for language list of type 'LANGLIST'
171 ***************************************************************************/
173 #define DELIM " \t" /* delimiters in language list */
182 * _enumLanglistStart() - start enumeration of languages and descriptions
184 * Dtlogin sets up the LANGLIST env var which contains the list
185 * of locale names to display in the language menus.
188 _enumLanglistStart(void)
191 struct _enumState *state = malloc(sizeof(struct _enumState));
195 if ((p = (char *)getenv(LANGLIST)) == NULL )
202 state->dupstr = strdup(p);
203 state->tokstr = state->dupstr;
207 return((void *)state);
211 * _enumLanglistNext() - get next language description pair
212 * note: *lang and *desc must be freed by free()
214 * Get next locale from LANGLIST and get possible description from
224 struct _enumState *enumstate = (struct _enumState *)state;
225 char *loclang, *locdesc;
227 loclang = strtok(enumstate->tokstr, DELIM);
228 if (enumstate->tokstr)
230 enumstate->tokstr = NULL;
235 if ((locdesc = GetLangName(loclang)) == NULL)
240 *lang = strdup(loclang);
241 *desc = strdup(locdesc);
249 * _enumLanglistEnd() - end enumeration of language names and descriptions
257 struct _enumState *enumstate = (struct _enumState *)state;
259 free(enumstate->dupstr);
263 /***************************************************************************
265 * Methods for language list
267 ***************************************************************************/
271 Boolean (*methodNext)();
277 * _enumLangStart() - start enumeration of languages and descriptions
279 * ENABLE_DYNAMIC_LANGLIST defined
280 * Enumerate LANGLIST. If unsucessful, try 'LangCmd'. LANGLIST will only
281 * be set if user specified Dtlogin*languageList.
283 * ENABLE_DYNAMIC_LANGLIST undefined
284 * Enumerate LANGLIST.
291 struct _enumObject *state = malloc(sizeof(struct _enumObject));
295 state->enumstate = _enumLanglistStart();
296 if (state->enumstate != NULL)
298 state->methodNext = _enumLanglistNext;
299 state->methodEnd = _enumLanglistEnd;
302 #if defined (ENABLE_DYNAMIC_LANGLIST)
303 if (state->enumstate == NULL)
305 state->enumstate = _enumLangCmdStart();
306 if (state->enumstate != NULL)
308 state->methodNext = _enumLangCmdNext;
309 state->methodEnd = _enumLangCmdEnd;
312 #endif /* ENABLE_DYNAMIC_LANGLIST */
314 if (state->enumstate == NULL)
321 return((void *)state);
325 * _enumLangNext() - get next language description pair
326 * note: *lang and *desc must be freed by free()
335 struct _enumObject *object = (struct _enumObject *)state;
337 rc = (*object->methodNext)(object->enumstate, lang, desc);
343 * _enumLangEnd() - end enumeration of language names and descriptions
349 struct _enumObject *object = (struct _enumObject *)state;
351 (*object->methodEnd)(object->enumstate);
356 /***************************************************************************
362 * The language menu contains the list of locales available to the
363 * the desktop session. This may be a subset of the actual installed
364 * locales. The list of locales to display in the language menu can
365 * be provided by the sysadmin, or determined by the login manager.
367 * * Sysadmin provided language list
369 * A sysadmin can set the Dtlogin.languageList resource to set the list
370 * of languages. The dtlogin process provides this list to dtgreet
371 * in the LANGLIST environment variable. This has priority.
373 * * Login manager determined language list
375 * If the sysadm does not set Dtlogin.languageList, ie. LANGLIST unset,
376 * the login manager will generate the list. There are two methods for
377 * doing this, one of which is selected at compile time with the
378 * ENABLE_DYNAMIC_LANGLIST define.
380 * * dynamic list (ENABLE_DYNAMIC_LANGLIST defined)
382 * This method executes the command specified by the
383 * Dtlogin*languageListCmd resource. The default is
384 * /usr/dt/bin/dtlslocale. The languageListCmd command is expected
385 * to write to stdout a series of language names and descriptions:
387 * lang_name description
388 * lang_name description
393 * En_US English (United States) - IBM-850
394 * Fr_BE French (Belgium) - IBM-850
396 * Also, since languageListCmd is run under dtgreet's locale, a
397 * localized description can be returned.
399 * * static list (ENABLE_DYNAMIC_LANGLIST undefined)
401 * This method has dtlogin querying the system and generating
402 * the language list to be provided to dtgreet via the LANGLIST
403 * environment variable. In this case dtlogin takes care to use the
404 * sysadmin provided list if necessary.
406 * * Language descriptions
408 * The sysadmin can set the Dtlogin*<lang>.languageName resource to
409 * provide a descriptive name for a particular language. If languageName
410 * unset, the value used depends on ENABLE_DYNAMIC_LANGLIST. If
411 * ENABLE_DYNAMIC_LANGLIST set, the value used is the descriptive text
412 * provided by languageListCmd. If ENABLE_DYNAMIC_LANGLIST unset, the value
413 * used is simply the locale name.
417 * The sysadmin can set the Dtlogin*language resource to specify the
418 * default language in the language menu.
420 ***************************************************************************/
422 #define MAX_LANG_ITEMS 16 /* maximum number of items in one lang menu */
423 #define MAX_NAME_LEN 128 /* maximum length of a language name */
426 char *lang; /* lang name ie En_US, Ja_JP */
427 char *desc; /* lang description ie English */
431 * compareLangDesc() - compare language descriptions in qsort()
438 return(strcmp(((struct Langlist *)first)->desc,
439 ((struct Langlist *)second)->desc));
447 char cblab[MAX_NAME_LEN]; /* pushbutton label */
448 int nlang; /* total number of languages */
449 int nlangMenus; /* number of language sub-menus */
450 int maxitems; /* max no. of items in sub-lang menu*/
456 char *lang; /* lang name ie En_US, Ja_JP */
457 char *desc; /* lang description ie English */
460 struct Langlist list[500];
464 * Generate list of langname/description pairs.
467 state = _enumLangStart();
470 while (_enumLangNext(state, &list[nlang].lang, &list[nlang].desc))
480 * Sort by description
482 qsort((char *)list, nlang, sizeof(list[0]), compareLangDesc);
485 * determine number of language sub-menus ...
486 * (MAX_LANG_ITEMS per menu)
492 maxitems = nlang/nlangMenus;
493 } while ( maxitems > MAX_LANG_ITEMS );
494 if (nlang%nlangMenus != 0) maxitems++; /* allow for stragglers */
498 * build language menu(s)...
501 lang_menu = XmCreatePulldownMenu(options_menu, "lang_menu", argt, i);
502 item_menu = lang_menu;
504 for (k = 0; k < nlang; k++) {
506 if ( nlangMenus > 1 && k%maxitems == 0) {
508 item_menu = XmCreatePulldownMenu(lang_menu, "item_menu",
513 * build toggle buttons...
515 i = InitArg(ToggleBG);
516 XtSetArg(argt[i], XmNrecomputeSize, True ); i++;
517 if (langenv && (strcmp(langenv, list[k].lang) == 0)) {
518 XtSetArg(argt[i], XmNset, True ); i++;
521 xmstr = XmStringCreateLocalized(list[k].desc);
522 XtSetArg(argt[i], XmNlabelString, xmstr ); i++;
524 button = XmCreateToggleButtonGadget(
525 item_menu, list[k].lang, argt, i);
526 XtAddCallback (button, XmNvalueChangedCallback,
527 RespondLangCB, (XtPointer) list[k].lang);
530 XtManageChild(button);
532 (char*) ReadCatalog(MC_LABEL_SET, MC_TO_LABEL, MC_DEF_TO_LABEL);
534 if ( nlangMenus > 1 && k%maxitems == 0 ) {
536 int last = k+maxitems >= nlang ? nlang-1 : k+maxitems-1;
538 i = InitArg(CascadeBG);
540 sprintf(cblab, "%s %s %s",
541 list[first].desc, tostr, list[last].desc);
543 xmstr = XmStringCreateLocalized(cblab);
544 XtSetArg(argt[i], XmNlabelString, xmstr ); i++;
545 XtSetArg(argt[i], XmNsubMenuId, item_menu ); i++;
546 XtSetArg(argt[i], XmNrecomputeSize, True ); i++;
547 button = XmCreateCascadeButtonGadget(lang_menu, cblab, argt, i);
548 XtManageChild(button);
555 for (k = 0; k < nlang; k++)
557 /* free(list[k].lang); -- used as callback data, don't free */