1 /*
2  * Copyright (c) 2003 Sasha Vasko <sasha at aftercode.net>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.   See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  *
18  */
19 
20 #define LOCAL_DEBUG
21 
22 #include "../configure.h"
23 #include "../libAfterStep/asapp.h"
24 #include "../libAfterStep/afterstep.h"
25 #include "../libAfterStep/parser.h"
26 #include "../libAfterStep/colorscheme.h"
27 #include "../libAfterStep/session.h"
28 #include "../libAfterStep/screen.h"
29 #include "../libAfterStep/kde.h"
30 #include "../libAfterBase/xml.h"
31 
32 #include <unistd.h>
33 
34 #include "afterconf.h"
35 
36 
37 /*****************************************************************************
38  *
39  * This routine is responsible for reading and parsing the colors config
40  * file
41  *
42  ****************************************************************************/
43 #define COLOR_TERM(n,len)  {TF_NO_MYNAME_PREPENDING, #n, len, TT_COLOR, COLOR_##n##_ID , NULL}
44 
45 TermDef ColorTerms[] = {
46 	COLOR_TERM (Base, 4),
47 	COLOR_TERM (Inactive1, 9),
48 	COLOR_TERM (Inactive2, 9),
49 	COLOR_TERM (Active, 6),
50 	COLOR_TERM (InactiveText1, 13),
51 	COLOR_TERM (InactiveText2, 13),
52 	COLOR_TERM (ActiveText, 10),
53 	COLOR_TERM (HighInactive, 12),
54 	COLOR_TERM (HighActive, 10),
55 	COLOR_TERM (HighInactiveBack, 16),
56 	COLOR_TERM (HighActiveBack, 14),
57 	COLOR_TERM (HighInactiveText, 16),
58 	COLOR_TERM (HighActiveText, 14),
59 	COLOR_TERM (DisabledText, 12),
60 	COLOR_TERM (BaseDark, 8),
61 	COLOR_TERM (BaseLight, 9),
62 	COLOR_TERM (Inactive1Dark, 13),
63 	COLOR_TERM (Inactive1Light, 14),
64 	COLOR_TERM (Inactive2Dark, 13),
65 	COLOR_TERM (Inactive2Light, 14),
66 	COLOR_TERM (ActiveDark, 10),
67 	COLOR_TERM (ActiveLight, 11),
68 	COLOR_TERM (HighInactiveDark, 16),
69 	COLOR_TERM (HighInactiveLight, 17),
70 	COLOR_TERM (HighActiveDark, 14),
71 	COLOR_TERM (HighActiveLight, 15),
72 	COLOR_TERM (HighInactiveBackDark, 20),
73 	COLOR_TERM (HighInactiveBackLight, 21),
74 	COLOR_TERM (HighActiveBackDark, 24),
75 	COLOR_TERM (HighActiveBackLight, 25),
76 	COLOR_TERM (Cursor, 7),
77 	{TF_NO_MYNAME_PREPENDING, "Angle", 5, TT_UINTEGER, COLOR_Angle_ID, NULL}
78 	,
79 
80 	{0, NULL, 0, 0, 0}
81 };
82 
83 
84 SyntaxDef ColorSyntax = {
85 	'\n',
86 	'\0',
87 	ColorTerms,
88 	0,														/* use default hash size */
89 	' ',
90 	"",
91 	"\t",
92 	"Custom Color Scheme",
93 	"ColorScheme",
94 	"defines color values for standard set of internal color names, to be used in other configuration files",
95 	NULL,
96 	0
97 };
98 
CreateColorConfig()99 ColorConfig *CreateColorConfig ()
100 {
101 	return safecalloc (1, sizeof (ColorConfig));
102 }
103 
DestroyColorConfig(ColorConfig * config)104 void DestroyColorConfig (ColorConfig * config)
105 {
106 	if (config) {
107 		DestroyFreeStorage (&(config->more_stuff));
108 		free (config);
109 	}
110 }
111 
112 
PrintColorConfig(ColorConfig * config)113 void PrintColorConfig (ColorConfig * config)
114 {
115 }
116 
ParseColorOptions(const char * filename,char * myname)117 ColorConfig *ParseColorOptions (const char *filename, char *myname)
118 {
119 	ColorConfig *config = CreateColorConfig ();
120 	FreeStorageElem *Storage = NULL, *pCurr;
121 	ConfigItem item;
122 
123 	Storage =
124 			file2free_storage (filename, myname, &ColorSyntax, NULL,
125 												 &(config->more_stuff));
126 	if (Storage == NULL)
127 		return config;
128 
129 	item.memory = NULL;
130 
131 	LOCAL_DEBUG_OUT ("Storage = %p", Storage);
132 
133 	for (pCurr = Storage; pCurr; pCurr = pCurr->next) {
134 		int index;
135 
136 		LOCAL_DEBUG_OUT ("pCurr = %p", pCurr);
137 		if (pCurr->term == NULL)
138 			continue;
139 		if (!ReadConfigItem (&item, pCurr))
140 			continue;
141 		index = pCurr->term->id - COLOR_ID_START;
142 		LOCAL_DEBUG_OUT ("id %d, index = %d", pCurr->term->id, index);
143 		if (index >= 0 && index < ASMC_MainColors) {
144 			LOCAL_DEBUG_OUT ("index %d is \"%s\"", index, item.data.string);
145 			if (parse_argb_color
146 					(item.data.string,
147 					 &(config->main_colors[index])) != item.data.string) {
148 				LOCAL_DEBUG_OUT ("Parsed color %d as #%8.8lX", index,
149 												 (unsigned long)config->main_colors[index]);
150 				set_flags (config->set_main_colors, (0x01 << index));
151 			}
152 		} else if (pCurr->term->id == COLOR_Angle_ID) {
153 			config->angle = item.data.integer;
154 			set_flags (config->set_main_colors, COLOR_Angle);
155 		}
156 		item.ok_to_free = 1;
157 	}
158 	ReadConfigItem (&item, NULL);
159 
160 	DestroyFreeStorage (&Storage);
161 	return config;
162 }
163 
164 /* returns:
165  *		0 on success
166  *		1 if data is empty
167  *		2 if ConfigWriter cannot be initialized
168  *
169  */
170 int
WriteColorOptions(const char * filename,char * myname,ColorConfig * config,unsigned long flags)171 WriteColorOptions (const char *filename, char *myname,
172 									 ColorConfig * config, unsigned long flags)
173 {
174 	ConfigDef *ColorConfigWriter = NULL;
175 	FreeStorageElem *Storage = NULL, **tail = &Storage;
176 	ConfigData cd;
177 
178 	char color_buffer[128];
179 	int i;
180 
181 	if (config == NULL)
182 		return 1;
183 	cd.filename = filename;
184 	if ((ColorConfigWriter =
185 			 InitConfigWriter (myname, &ColorSyntax, CDT_Filename, cd)) == NULL)
186 		return 2;
187 
188 	CopyFreeStorage (&Storage, config->more_stuff);
189 
190 	/* building free storage here */
191 	LOCAL_DEBUG_OUT ("0x%lX", config->set_main_colors);
192 	for (i = 0; i < ASMC_MainColors; ++i) {
193 		ARGB32 c = config->main_colors[i];
194 		CARD32 a, r, g, b, h, s, v;
195 		char *tmp[1];
196 		FreeStorageElem **pelem;
197 
198 		a = ARGB32_ALPHA8 (c);
199 		r = ARGB32_RED16 (c);
200 		g = ARGB32_GREEN16 (c);
201 		b = ARGB32_BLUE16 (c);
202 		h = rgb2hsv (r, g, b, &s, &v);
203 		h = hue162degrees (h);
204 		s = val162percent (s);
205 		v = val162percent (v);
206 		r = r >> 8;
207 		g = g >> 8;
208 		b = b >> 8;
209 		tmp[0] = &(color_buffer[0]);
210 		sprintf (color_buffer,
211 						 "#%2.2lX%2.2lX%2.2lX%2.2lX  \t\t# or ahsv(%ld,%ld,%ld,%ld) or argb(%ld,%ld,%ld,%ld)",
212 						 (unsigned long)a, (unsigned long)r, (unsigned long)g,
213 						 (unsigned long)b, (long)a, (long)h, (long)s, (long)v, (long)a,
214 						 (long)r, (long)g, (long)b);
215 		pelem = tail;
216 		LOCAL_DEBUG_OUT ("tail  = %p", tail);
217 		tail =
218 				Strings2FreeStorage (&ColorSyntax, tail, &(tmp[0]), 1,
219 														 COLOR_ID_START + i);
220 
221 		LOCAL_DEBUG_OUT ("i = %d, tail  = %p, *pelem = %p", i, tail, pelem);
222 		if (*pelem && !get_flags (config->set_main_colors, 0x01 << i)
223 				&& i != ASMC_Base)
224 			set_flags ((*pelem)->flags, CF_DISABLED_OPTION);
225 	}
226 
227 	/* colorscheme angle */
228 	if (get_flags (config->set_main_colors, COLOR_Angle))
229 		tail =
230 				Integer2FreeStorage (&ColorSyntax, tail, NULL, config->angle,
231 														 COLOR_Angle_ID);
232 
233 	/* writing config into the file */
234 	cd.filename = filename;
235 	WriteConfig (ColorConfigWriter, Storage, CDT_Filename, &cd, flags);
236 	DestroyFreeStorage (&Storage);
237 	DestroyConfig (ColorConfigWriter);
238 
239 	if (Storage) {
240 		fprintf (stderr,
241 						 "\n%s:Config Writing warning: Not all Free Storage discarded! Trying again...",
242 						 myname);
243 		DestroyFreeStorage (&Storage);
244 		fprintf (stderr, (Storage != NULL) ? " failed." : " success.");
245 	}
246 	return 0;
247 }
248 
ASColorScheme2ColorConfig(ASColorScheme * cs)249 ColorConfig *ASColorScheme2ColorConfig (ASColorScheme * cs)
250 {
251 	ColorConfig *config = NULL;
252 
253 	if (cs) {
254 		int i;
255 
256 		config = CreateColorConfig ();
257 		config->angle = cs->angle;
258 		for (i = 0; i < ASMC_MainColors; ++i)
259 			config->main_colors[i] = cs->main_colors[i];
260 		config->set_main_colors = cs->set_main_colors;
261 	}
262 	return config;
263 }
264 
ColorConfig2ASColorScheme(ColorConfig * config)265 ASColorScheme *ColorConfig2ASColorScheme (ColorConfig * config)
266 {
267 	ASColorScheme *cs = NULL;
268 
269 	if (config) {
270 		int i;
271 		int angle = ASCS_DEFAULT_ANGLE;
272 
273 		if (get_flags (config->set_main_colors, COLOR_Angle))
274 			angle = config->angle;
275 		cs = make_ascolor_scheme (config->main_colors[ASMC_Base], angle);
276 		for (i = 0; i < ASMC_MainColors; ++i)
277 			if (i != ASMC_Base
278 					&& get_flags (config->set_main_colors, (0x01 << i)))
279 				cs->main_colors[i] = config->main_colors[i];
280 
281 		for (i = 0; i < ASMC_MainColors; ++i)
282 			make_color_scheme_hsv (cs->main_colors[i], &(cs->main_hues[i]),
283 														 &(cs->main_saturations[i]),
284 														 &(cs->main_values[i]));
285 
286 		cs->set_main_colors = config->set_main_colors;
287 	}
288 	return cs;
289 }
290 
LoadColorScheme()291 void LoadColorScheme ()
292 {
293 	ASColorScheme *cs = NULL;
294 	const char *const_configfile;
295 
296 	/* first we need to load the colorscheme */
297 	if ((const_configfile =
298 			 get_session_file (Session, get_screen_current_desk (NULL),
299 												 F_CHANGE_COLORSCHEME, False)) != NULL) {
300 		ColorConfig *config = ParseColorOptions (const_configfile, MyName);
301 
302 		if (config) {
303 			cs = ColorConfig2ASColorScheme (config);
304 			DestroyColorConfig (config);
305 			show_progress ("COLORSCHEME loaded from \"%s\" ...",
306 										 const_configfile);
307 		} else
308 			show_progress
309 					("COLORSCHEME file format is unrecognizeable in \"%s\" ...",
310 					 const_configfile);
311 
312 	} else
313 		show_warning ("COLORSCHEME is not set");
314 
315 	if (cs == NULL)
316 		cs = make_default_ascolor_scheme ();
317 
318 	populate_ascs_colors_rgb (cs);
319 	populate_ascs_colors_xml (cs);
320 	free (cs);
321 }
322 
323 Bool
translate_gtkrc_template_file(const char * template_fname,const char * output_fname)324 translate_gtkrc_template_file (const char *template_fname,
325 															 const char *output_fname)
326 {
327 	static char buffer[MAXLINELENGTH];
328 	FILE *src_fp = NULL, *dst_fp = NULL;
329 	int good_strings = 0;
330 
331 	if (template_fname == NULL || output_fname == NULL)
332 		return False;;
333 
334 	src_fp = fopen (template_fname, "r");
335 	dst_fp = fopen (output_fname, "w");
336 	if (dst_fp == NULL)
337 		show_warning ("Failed to open file \"%s\" for writing", output_fname);
338 	if (src_fp != NULL && dst_fp != NULL) {
339 		while (fgets (&buffer[0], MAXLINELENGTH, src_fp)) {
340 			int i = 0;
341 
342 			while (isspace (buffer[i]))
343 				++i;
344 			if (buffer[i] != '\n' && buffer[i] != '#' && buffer[i] != '\0'
345 					&& buffer[i] != '\r') {
346 				++good_strings;
347 				if (strncmp (&buffer[i], "fg[", 3) == 0 ||
348 						strncmp (&buffer[i], "bg[", 3) == 0 ||
349 						strncmp (&buffer[i], "text[", 5) == 0 ||
350 						strncmp (&buffer[i], "base[", 5) == 0 ||
351 						strncmp (&buffer[i], "light[", 6) == 0 ||
352 						strncmp (&buffer[i], "dark[", 5) == 0
353 						|| strncmp (&buffer[i], "mid[", 4) == 0) {
354 					while (buffer[i] != '\0' && buffer[i] != '\"'
355 								 && buffer[i] != '\{')
356 						++i;
357 					if (buffer[i] == '\"') {
358 						char *token = &buffer[i + 1];
359 
360 						if (isalpha (token[0])) {
361 							int len = 0;
362 
363 							while (token[len] != '\0' && token[len] != '\"')
364 								++len;
365 							if (token[len] == '\"' && len > 0) {
366 								ARGB32 argb;
367 
368 								if (parse_argb_color (token, &argb) != token) {
369 									fwrite (&(buffer[0]), 1, i + 1, dst_fp);
370 									fprintf (dst_fp, "#%2.2lX%2.2lX%2.2lX",
371 													 (unsigned long)ARGB32_RED8 (argb),
372 													 (unsigned long)ARGB32_GREEN8 (argb),
373 													 (unsigned long)ARGB32_BLUE8 (argb));
374 									fwrite (&(token[len]), 1, strlen (&(token[len])),
375 													dst_fp);
376 									continue;
377 								}
378 							}
379 						}
380 					}
381 				}
382 			}
383 			fwrite (&buffer[0], 1, strlen (&buffer[0]), dst_fp);
384 		}
385 
386 	}
387 	if (src_fp)
388 		fclose (src_fp);
389 	if (dst_fp)
390 		fclose (dst_fp);
391 	return (good_strings > 0);
392 }
393 
394 Bool
translate_kcsrc_template_file(const char * template_fname,const char * output_fname)395 translate_kcsrc_template_file (const char *template_fname,
396 															 const char *output_fname)
397 {
398 /* this prolly needs to be rewritten using libAfterBase/kde.c code	: */
399 	int good_strings = 0;
400 	xml_elem_t *KDE_cs, *group;
401 
402 	if (template_fname == NULL || output_fname == NULL)
403 		return False;;
404 
405 	KDE_cs = load_KDE_config (template_fname);
406 	for (group = KDE_cs->child; group != NULL; group = group->next) {
407 		xml_elem_t *item;
408 
409 		for (item = group->child; item != NULL; item = item->next)
410 			if (item->tag_id == KDEConfig_item && IsTagCDATA (item->child)) {
411 				char *parm = item->child->parm;
412 
413 				++good_strings;
414 				if (*parm == '\"') {
415 					ARGB32 argb;
416 
417 					++parm;
418 					if (parse_argb_color (parm, &argb) != parm) {
419 						char *tmp = safemalloc (32);
420 
421 						sprintf (tmp, "%ld,%ld,%ld", (unsigned long)ARGB32_RED8 (argb),
422 										 (unsigned long)ARGB32_GREEN8 (argb),
423 										 (unsigned long)ARGB32_BLUE8 (argb));
424 						free (item->child->parm);
425 						item->child->parm = tmp;
426 					}
427 				}
428 			}
429 	}
430 	save_KDE_config (output_fname, KDE_cs);
431 	xml_elem_delete (NULL, KDE_cs);
432 
433 	return (good_strings > 0);
434 }
435 
436 
UpdateGtkRC(ASEnvironment * e)437 Bool UpdateGtkRC (ASEnvironment * e)
438 {
439 	Bool result = False;
440 	char *src;
441 
442 	/* first we need to load the colorscheme */
443 	if (e == NULL)
444 		return False;
445 	if (e->gtkrc_path != NULL && strcmp (e->gtkrc_path, "/dev/null") != 0) {
446 		src = make_session_file (Session, GTKRC_TEMPLATE_FILE, False);
447 		if (src)
448 			result = translate_gtkrc_template_file (src, e->gtkrc_path);
449 
450 		destroy_string (&src);
451 	}
452 
453 	if (e->gtkrc20_path != NULL
454 			&& strcmp (e->gtkrc20_path, "/dev/null") != 0) {
455 		src = make_session_file (Session, GTKRC20_TEMPLATE_FILE, False);
456 		/* first we need to load the colorscheme */
457 		if (src)
458 			if (translate_gtkrc_template_file (src, e->gtkrc20_path))
459 				result = True;
460 		destroy_string (&src);
461 	}
462 	return result;
463 }
464 
465 static Bool
SetKDEGlobalsColorScheme(const char * new_cs_file,const char * cs_name)466 SetKDEGlobalsColorScheme (const char *new_cs_file, const char *cs_name)
467 {
468 	char *kdeglobals_fname = copy_replace_envvar (KDEGLOBALS_FILE);
469 	xml_elem_t *KDE_cs = load_KDE_config (new_cs_file);
470 	xml_elem_t *KDE_globals = load_KDE_config (kdeglobals_fname);
471 	xml_elem_t *KDE_group = get_KDE_config_group (KDE_globals, "KDE", True);
472 	xml_elem_t *CS_group =
473 			get_KDE_config_group (KDE_cs, "Color Scheme", False);
474 
475 	if (CS_group) {
476 		xml_elem_t *WM_group = get_KDE_config_group (KDE_globals, "WM", True);
477 		xml_elem_t *General_group =
478 				get_KDE_config_group (KDE_globals, "General", True);
479 
480 		merge_KDE_config_groups (CS_group, WM_group);
481 		merge_KDE_config_groups (CS_group, General_group);
482 	}
483 
484 	set_KDE_config_group_item (KDE_group, "colorScheme",
485 														 cs_name ? cs_name : new_cs_file);
486 
487 	save_KDE_config (kdeglobals_fname, KDE_globals);
488 	xml_elem_delete (NULL, KDE_globals);
489 	xml_elem_delete (NULL, KDE_cs);
490 
491 	free (kdeglobals_fname);
492 
493 	add_KDE_colorscheme (new_cs_file);
494 	return (CS_group != NULL);
495 }
496 
UpdateKCSRC()497 Bool UpdateKCSRC ()
498 {
499 	Bool result = False;
500 	char *src = make_session_file (Session, KSCRC_TEMPLATE_FILE, False);
501 	char *dst = make_session_rc_file (Session, KCSRC_FILE);
502 
503 	/* first we need to load the colorscheme */
504 	if (src && dst)
505 		result = translate_kcsrc_template_file (src, dst);
506 
507 	if (result) {
508 		char *cs_filename = dst;
509 		char *kcs_path = copy_replace_envvar (KDECS_DIR);
510 
511 		if (CheckDir (kcs_path) == 0) {
512 			char *fullcs_filename;
513 
514 			cs_filename = mystrdup (AS_KCSRC_FILE);
515 			fullcs_filename = make_file_name (kcs_path, cs_filename);
516 			CopyFile (dst, fullcs_filename);
517 			free (fullcs_filename);
518 		}
519 		free (kcs_path);
520 
521 		if (!SetKDEGlobalsColorScheme (dst, cs_filename))
522 			result = False;
523 		if (cs_filename != dst)
524 			free (cs_filename);
525 	}
526 	destroy_string (&src);
527 	destroy_string (&dst);
528 
529 	return result;
530 }
531 
532 
533 #if 0
534 /* relevant KDE code for reference : */
535 
536 void KColorScheme::load ()
537 {
538 	KConfig *config = KGlobal::config ();
539 
540 	config->setGroup ("KDE");
541 	QString currentScheme = config->readEntry ("colorScheme");
542 
543 	QString currentSchemeSearch =
544 			currentScheme.left (currentScheme.length () -
545 													QString (".kcsrc").length ());
546 
547 	if (SchemeListItem * item = findSchemeListItem (currentSchemeSearch)) {
548 		item->setSelected (true);
549 		m_ui->schemeList->setCurrentItem (item);
550 		m_ui->schemeList->ensureItemVisible (item);
551 	}
552 	m_currentScheme->setInheritedScheme (currentSchemeSearch);
553 	currentSchemeChanged ();
554 
555 	KConfig cfg ("kcmdisplayrc", true, false);
556 
557 	cfg.setGroup ("X11");
558 	bool exportColors = cfg.readBoolEntry ("exportKDEColors", true);
559 
560 	m_ui->exportColorsCB->setChecked (exportColors);
561 
562 	emit changed (false);
563 }
564 
565 
566 
567 
568 void KColorScheme::save ()
569 {
570 	// apply the current scheme data
571 	if (m_selectedScheme && m_currentScheme) {
572 		KConfig *c = KGlobal::config ();
573 
574 		writeSchemeConfig (c, "General", "WM", "KDE", *m_currentScheme);
575 // this also translates into :
576 		KConfig *cfg = KGlobal::config ();
577 
578 		cfg->setGroup ("General");
579 		cfg->writeEntry ("background", cs->back, true, true);
580 		cfg->writeEntry ("selectBackground", cs->select, true, true);
581 		cfg->writeEntry ("foreground", cs->txt, true, true);
582 		cfg->writeEntry ("windowForeground", cs->windowTxt, true, true);
583 		cfg->writeEntry ("windowBackground", cs->window, true, true);
584 		cfg->writeEntry ("selectForeground", cs->selectTxt, true, true);
585 		cfg->writeEntry ("buttonBackground", cs->button, true, true);
586 		cfg->writeEntry ("buttonForeground", cs->buttonTxt, true, true);
587 
588 		cfg->setGroup ("WM");
589 		cfg->writeEntry ("activeForeground", cs->aTxt, true, true);
590 		cfg->writeEntry ("inactiveBackground", cs->iaTitle, true, true);
591 		cfg->writeEntry ("inactiveBlend", cs->iaBlend, true, true);
592 		cfg->writeEntry ("activeBackground", cs->aTitle, true, true);
593 		cfg->writeEntry ("activeBlend", cs->aBlend, true, true);
594 		cfg->writeEntry ("inactiveForeground", cs->iaTxt, true, true);
595 		cfg->writeEntry ("activeTitleBtnFg", cs->aTitleBtn, true, true);
596 		cfg->writeEntry ("inactiveTitleBtnFg", cs->iTitleBtn, true, true);
597 		cfg->writeEntry ("activeTitleBtnBg", cs->aTitleBtnBack, true, true);
598 		cfg->writeEntry ("inactiveTitleBtnBg", cs->iTitleBtnBack, true, true);
599 		if (cs->aTitleBtnBlend != cs->aTitleBtnBack)
600 			cfg->writeEntry ("activeTitleBtnBlend", cs->aTitleBtnBlend, true,
601 											 true);
602 		else
603 			cfg->writeEntry ("activeTitleBtnBlend", "", true, true);
604 		if (cs->iTitleBtnBlend != cs->iTitleBtnBack)
605 			cfg->writeEntry ("inactiveTitleBtnBlend", cs->iTitleBtnBlend, true,
606 											 true);
607 		else
608 			cfg->writeEntry ("inactiveTitleBtnBlend", "", true, true);
609 
610 		cfg->setGroup ("KDE");
611 		cfg->writeEntry ("contrast", cs->contrast, true, true);
612 		cfg->sync ();
613 
614 		c->writeEntry ("colorScheme",
615 									 QString ("%1.kcsrc").arg (m_selectedScheme->
616 																						 visibleName ()), true, true);
617 		c->sync ();
618 
619 		// KDE-1.x support
620 		KSimpleConfig *c2 =
621 				new KSimpleConfig (QDir::homeDirPath () + "/.kderc");
622 
623 		c2->setGroup ("General");
624 		write (c2, CS_StandardBackground, *m_currentScheme);
625 		write (c2, CS_SelecedBackground, *m_currentScheme);
626 		write (c2, CS_Text, *m_currentScheme);
627 		write (c2, CS_StandardText, *m_currentScheme);
628 		write (c2, CS_Background, *m_currentScheme);
629 		write (c2, CS_SelectedText, *m_currentScheme);
630 		c2->sync ();
631 		delete c2;
632 	}
633 
634 	KConfig cfg2 ("kcmdisplayrc", false, false);
635 
636 	cfg2.setGroup ("X11");
637 	bool exportColors = m_ui->exportColorsCB->isChecked ();
638 
639 	cfg2.writeEntry ("exportKDEColors", exportColors);
640 	cfg2.sync ();
641 	QApplication::syncX ();
642 
643 	// Notify all qt-only apps of the KDE palette changes
644 	uint flags = KRdbExportQtColors;
645 
646 	if (exportColors)
647 		flags |= KRdbExportColors;
648 	else {
649 #if defined Q_WS_X11 && !defined K_WS_QTONLY
650 		// Undo the property xrdb has placed on the root window (if any),
651 		// i.e. remove all entries, including ours
652 		XDeleteProperty (qt_xdisplay (), qt_xrootwin (), XA_RESOURCE_MANAGER);
653 #endif
654 	}
655 	runRdb (flags);								// Save the palette to qtrc for KStyles
656 
657 	// Notify all KDE applications
658 	KIPC::sendMessageAll (KIPC::PaletteChanged);
659 
660 	emit changed (false);
661 }
662 
663 void runRdb (uint flags)
664 {
665 	// Obtain the application palette that is about to be set.
666 	QPalette newPal = KApplication::createApplicationPalette ();
667 	bool exportColors = flags & KRdbExportColors;
668 	bool exportQtColors = flags & KRdbExportQtColors;
669 	bool exportQtSettings = flags & KRdbExportQtSettings;
670 	bool exportXftSettings = flags & KRdbExportXftSettings;
671 
672 	KConfig kglobals ("kdeglobals", true, false);
673 
674 	kglobals.setGroup ("KDE");
675 
676 	KTempFile tmpFile;
677 
678 	if (tmpFile.status () != 0) {
679 		kdDebug () << "Couldn't open temp file" << endl;
680 		exit (0);
681 	}
682 
683 	QFile & tmp = *(tmpFile.file ());
684 
685 	// Export colors to non-(KDE/Qt) apps (e.g. Motif, GTK+ apps)
686 	if (exportColors) {
687 		KGlobal::dirs ()->addResourceType ("appdefaults",
688 																			 KStandardDirs::
689 																			 kde_default ("data") +
690 																			 "kdisplay/app-defaults/");
691 		QColorGroup cg = newPal.active ();
692 
693 		KGlobal::locale ()->insertCatalogue ("krdb");
694 		createGtkrc (true, cg, 1);
695 		createGtkrc (true, cg, 2);
696 
697 		QString preproc;
698 		QColor backCol = cg.background ();
699 
700 		addColorDef (preproc, "FOREGROUND", cg.foreground ());
701 		addColorDef (preproc, "BACKGROUND", backCol);
702 		addColorDef (preproc, "HIGHLIGHT",
703 								 backCol.light (100 +
704 																(2 * KGlobalSettings::contrast () +
705 																 4) * 16 / 1));
706 		addColorDef (preproc, "LOWLIGHT",
707 								 backCol.dark (100 +
708 															 (2 * KGlobalSettings::contrast () +
709 																4) * 10));
710 		addColorDef (preproc, "SELECT_BACKGROUND", cg.highlight ());
711 		addColorDef (preproc, "SELECT_FOREGROUND", cg.highlightedText ());
712 		addColorDef (preproc, "WINDOW_BACKGROUND", cg.base ());
713 		addColorDef (preproc, "WINDOW_FOREGROUND", cg.foreground ());
714 		addColorDef (preproc, "INACTIVE_BACKGROUND",
715 								 KGlobalSettings::inactiveTitleColor ());
716 		addColorDef (preproc, "INACTIVE_FOREGROUND",
717 								 KGlobalSettings::inactiveTitleColor ());
718 		addColorDef (preproc, "ACTIVE_BACKGROUND",
719 								 KGlobalSettings::activeTitleColor ());
720 		addColorDef (preproc, "ACTIVE_FOREGROUND",
721 								 KGlobalSettings::activeTitleColor ());
722 		//---------------------------------------------------------------
723 
724 		tmp.writeBlock (preproc.latin1 (), preproc.length ());
725 
726 		QStringList list;
727 
728 		QStringList adPaths = KGlobal::dirs ()->findDirs ("appdefaults", "");
729 
730 		for (QStringList::ConstIterator it = adPaths.begin ();
731 				 it != adPaths.end (); ++it) {
732 			QDir dSys (*it);
733 
734 			if (dSys.exists ()) {
735 				dSys.setFilter (QDir::Files);
736 				dSys.setSorting (QDir::Name);
737 				dSys.setNameFilter ("*.ad");
738 				list += dSys.entryList ();
739 			}
740 		}
741 
742 		for (QStringList::ConstIterator it = list.begin (); it != list.end ();
743 				 it++)
744 			copyFile (tmp, locate ("appdefaults", *it), true);
745 	}
746 	// Merge ~/.Xresources or fallback to ~/.Xdefaults
747 	QString homeDir = QDir::homeDirPath ();
748 	QString xResources = homeDir + "/.Xresources";
749 
750 	// very primitive support for ~/.Xresources by appending it
751 	if (QFile::exists (xResources))
752 		copyFile (tmp, xResources, true);
753 	else
754 		copyFile (tmp, homeDir + "/.Xdefaults", true);
755 
756 	// Export the Xcursor theme & size settings
757 	QString theme = kglobals.readEntry ("cursorTheme", QString ());
758 	QString size = kglobals.readEntry ("cursorSize", QString ());
759 	QString contents;
760 
761 	if (!theme.isNull ())
762 		contents = "Xcursor.theme: " + theme + '\n';
763 
764 	if (!size.isNull ())
765 		contents += "Xcursor.size: " + size + '\n';
766 
767 	if (exportXftSettings) {
768 		kglobals.setGroup ("General");
769 
770 		QString hintStyle (kglobals.readEntry ("XftHintStyle", "hintmedium")),
771 				subPixel (kglobals.readEntry ("XftSubPixel"));
772 
773 		contents += "Xft.antialias: ";
774 		if (QSettings ().readBoolEntry ("/qt/useXft"))
775 			contents += "1";
776 		else
777 			contents += "0";
778 
779 		contents += "\nXft.hinting: ";
780 		if (hintStyle.isEmpty ())
781 			contents += "-1";
782 		else {
783 			if (hintStyle != "hintnone")
784 				contents += "1";
785 			else
786 				contents += "0";
787 			contents += "\nXft.hintstyle: " + hintStyle + '\n';
788 		}
789 		if (!subPixel.isEmpty ())
790 			contents += "Xft.rgba: " + subPixel + '\n';
791 	}
792 
793 	if (contents.length () > 0)
794 		tmp.writeBlock (contents.latin1 (), contents.length ());
795 
796 	tmpFile.close ();
797 
798 	KProcess proc;
799 
800 #ifndef NDEBUG
801 	proc << "xrdb" << "-merge" << tmpFile.name ();
802 #else
803 	proc << "xrdb" << "-quiet" << "-merge" << tmpFile.name ();
804 #endif
805 	proc.start (KProcess::Block, KProcess::Stdin);
806 
807 	tmpFile.unlink ();
808 
809 	applyGtkStyles (exportColors, 1);
810 	applyGtkStyles (exportColors, 2);
811 
812 	/* Qt exports */
813 	if (exportQtColors || exportQtSettings) {
814 		QSettings *settings = new QSettings;
815 
816 		if (exportQtColors)
817 			applyQtColors (kglobals, *settings, newPal);	// For kcmcolors
818 
819 		if (exportQtSettings)
820 			applyQtSettings (kglobals, *settings);	// For kcmstyle
821 
822 		delete settings;
823 
824 		QApplication::flushX ();
825 
826 		// We let KIPC take care of ourselves, as we are in a KDE app with
827 		// QApp::setDesktopSettingsAware(false);
828 		// Instead of calling QApp::x11_apply_settings() directly, we instead
829 		// modify the timestamp which propagates the settings changes onto
830 		// Qt-only apps without adversely affecting ourselves.
831 
832 		// Cheat and use the current timestamp, since we just saved to qtrc.
833 		QDateTime settingsstamp = QDateTime::currentDateTime ();
834 
835 		static Atom qt_settings_timestamp = 0;
836 
837 		if (!qt_settings_timestamp) {
838 			QString atomname ("_QT_SETTINGS_TIMESTAMP_");
839 
840 			atomname += XDisplayName (0);	// Use the $DISPLAY envvar.
841 			qt_settings_timestamp =
842 					XInternAtom (qt_xdisplay (), atomname.latin1 (), False);
843 		}
844 
845 		QBuffer stamp;
846 		QDataStream s (stamp.buffer (), IO_WriteOnly);
847 
848 		s << settingsstamp;
849 		XChangeProperty (qt_xdisplay (), qt_xrootwin (), qt_settings_timestamp,
850 										 qt_settings_timestamp, 8, PropModeReplace,
851 										 (unsigned char *)stamp.buffer ().data (),
852 										 stamp.buffer ().size ());
853 		QApplication::flushX ();
854 	}
855 }
856 
857 static void
858 applyQtColors (KConfig & kglobals, QSettings & settings, QPalette & newPal)
859 {
860 	QStringList actcg, inactcg, discg;
861 
862 	/* export kde color settings */
863 	int i;
864 
865 	for (i = 0; i < QColorGroup::NColorRoles; i++)
866 		actcg << newPal.color (QPalette::Active,
867 													 (QColorGroup::ColorRole) i).name ();
868 	for (i = 0; i < QColorGroup::NColorRoles; i++)
869 		inactcg << newPal.color (QPalette::Inactive,
870 														 (QColorGroup::ColorRole) i).name ();
871 	for (i = 0; i < QColorGroup::NColorRoles; i++)
872 		discg << newPal.color (QPalette::Disabled,
873 													 (QColorGroup::ColorRole) i).name ();
874 
875 	while (!settings.writeEntry ("/qt/Palette/active", actcg)) ;
876 	settings.writeEntry ("/qt/Palette/inactive", inactcg);
877 	settings.writeEntry ("/qt/Palette/disabled", discg);
878 
879 	// export kwin's colors to qtrc for kstyle to use
880 	kglobals.setGroup ("WM");
881 
882 	// active colors
883 	QColor clr = newPal.active ().background ();
884 
885 	clr = kglobals.readColorEntry ("activeBackground", &clr);
886 	settings.writeEntry ("/qt/KWinPalette/activeBackground", clr.name ());
887 	if (QPixmap::defaultDepth () > 8)
888 		clr = clr.dark (110);
889 	clr = kglobals.readColorEntry ("activeBlend", &clr);
890 	settings.writeEntry ("/qt/KWinPalette/activeBlend", clr.name ());
891 	clr = newPal.active ().highlightedText ();
892 	clr = kglobals.readColorEntry ("activeForeground", &clr);
893 	settings.writeEntry ("/qt/KWinPalette/activeForeground", clr.name ());
894 	clr = newPal.active ().background ();
895 	clr = kglobals.readColorEntry ("frame", &clr);
896 	settings.writeEntry ("/qt/KWinPalette/frame", clr.name ());
897 	clr = kglobals.readColorEntry ("activeTitleBtnBg", &clr);
898 	settings.writeEntry ("/qt/KWinPalette/activeTitleBtnBg", clr.name ());
899 
900 	// inactive colors
901 	clr = newPal.inactive ().background ();
902 	clr = kglobals.readColorEntry ("inactiveBackground", &clr);
903 	settings.writeEntry ("/qt/KWinPalette/inactiveBackground", clr.name ());
904 	if (QPixmap::defaultDepth () > 8)
905 		clr = clr.dark (110);
906 	clr = kglobals.readColorEntry ("inactiveBlend", &clr);
907 	settings.writeEntry ("/qt/KWinPalette/inactiveBlend", clr.name ());
908 	clr = newPal.inactive ().background ().dark ();
909 	clr = kglobals.readColorEntry ("inactiveForeground", &clr);
910 	settings.writeEntry ("/qt/KWinPalette/inactiveForeground", clr.name ());
911 	clr = newPal.inactive ().background ();
912 	clr = kglobals.readColorEntry ("inactiveFrame", &clr);
913 	settings.writeEntry ("/qt/KWinPalette/inactiveFrame", clr.name ());
914 	clr = kglobals.readColorEntry ("inactiveTitleBtnBg", &clr);
915 	settings.writeEntry ("/qt/KWinPalette/inactiveTitleBtnBg", clr.name ());
916 
917 	kglobals.setGroup ("KDE");
918 	settings.writeEntry ("/qt/KDE/contrast",
919 											 kglobals.readNumEntry ("contrast", 7));
920 }
921 
922 #endif
923