Endolith (owner)

Revisions

gist: 74192 Download_button fork
public
Description:
Gnome to Wine color scraper
Public Clone URL: git://gist.github.com/74192.git
Embed All Files: show embed
Readme.txt #
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
This is a Python script to extract GNOME/GTK's color scheme and apply it to Wine, so that the themes (approximately) match.
 
Instructions:
1. Set your Gnome theme as you would like it
2. Run with a command like "python wine_colors_from_gtk.py"
3. Restart any apps running in Wine. They should match the Gnome theme colors now.
 
Better description with screenshots here: http://www.endolith.com/wordpress/2008/08/03/wine-colors/
 
This is also stored on https://code.launchpad.net/~endolith/+junk/wine-color-scraper
Just trying out gist.github.com...
 
 
To do:
 
* Needs to separate out scrapers for each GTK engine where necessary. (Can't an interface for this just be built into the engines instead?)
* Copy Gnome fonts as well as colors. (Not sure where Wine stores these settings.)
* Something would need to call this script every time the Gnome theme is changed.
 
Everything else is working for me.
 
Other previous discussions:
http://ubuntuforums.org/showthread.php?t=55286&page=3#29
http://ubuntuforums.org/showthread.php?t=878068
http://www.mail-archive.com/pygtk@daa.com.au/msg16400.html
http://www.mail-archive.com/gtk-app-devel-list@gnome.org/msg12076.html
http://www.wine-doors.org/trac/ticket/411
 
wineconfig.py and winewrite.py scripts in Guidance package for KDE do the same things:
 
http://kde-guidance.sourcearchive.com/documentation/0.8.0-0ubuntu5/dir_b125788d4a71372d5142465501c18d05.html
 
Similar code is built into Mozilla:
 
http://www.google.com/codesearch/p?hl=en#e_ObwTAVPyo/widget/src/gtk2/nsLookAndFeel.cpp&q=nsLookAndFeel.cpp
 
Will be integrated into Wine Doors? http://www.wine-doors.org/trac/changeset/1536
wine_colors_from_gtk.py #
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
#!/usr/bin/env python
 
# Scrape colors from GTK and import them into Wine through the registry
#
# endolith@gmail.com 2009-02-06
#
# Based on script by KillerKiwi [Ubuntu Forums] October 29th, 2007
# http://ubuntuforums.org/showthread.php?t=55286&page=3#23
#
# which is based on patch by Johannes Roith [Mono-winforms-list] Wed, 27 Aug 2003
# http://lists.ximian.com/pipermail/mono-winforms-list/2003-August/000469.html
 
 
import pygtk
import gtk
import os
from tempfile import NamedTemporaryFile
from gconf import Client
import re
 
 
# TODO: command line switch
debug_mode = False
 
def format_color_string(Color):
    """ Convert 48-bit gdk.Color to 24-bit 'RRR GGG BBB' triple. """
    if type(Color) is gtk.gdk.Color:
        return '%s %s %s' % (Color.red/256, Color.green/256, Color.blue/256)
    else:
        print('Not a GdkColor: ' + str(Color))
        return None
 
def format_hex_color(color):
    """ Convert from hex color string to decimal 'RRR GGG BBB' triple. """
    if re.match('^#[0-9a-fA-F]{12}$', color):
        r, g, b = color[1:3], color[5:7], color[9:11] #rrrrggggbbbb
    elif re.match('^#[0-9a-fA-F]{6}$', color):
        r, g, b = color[1:3], color[3:5], color[5:7] #RRGGBB
    elif re.match('^#[0-9a-fA-F]{3}$', color):
        r, g, b = color[1]*2, color[2]*2, color[3]*2 #09C becomes 0099CC.
    else:
        print('Cannot understand color string format: ' + str(color))
        return None
    return '%s %s %s' % (int(r,16), int(g,16), int(b,16))
 
# TODO: fonts
 
# Get some colors from GTK
# gtk.Style object:
# http://www.moeraki.com/pygtkreference/pygtk2reference/class-gtkstyle.html
 
# Create a window to scrape colors from
window = gtk.Window()
 
button = gtk.Button()
vbox = gtk.VBox()
vbox.add(button)
 
scrollbar = gtk.VScrollbar()
vbox.add(scrollbar)
 
menubar = gtk.MenuBar()
menuitem = gtk.MenuItem()
menubar.add(menuitem)
vbox.add(menubar)
 
window.add(vbox)
 
# On show_all(), these are all converted from gtk.Style objects with wrong
# colors into __main__.EngineStyle objects with correct colors.
window.show_all()
 
# Tooltips
# http://www.daa.com.au/pipermail/pygtk/2005-November/011353.html
tooltip = gtk.Window()
tooltip.set_name('gtk-tooltips')
tooltip.show_all()
 
# All of Wine's 31 possible user.reg color values
# Asterisk * next to comment if I've found a value that works for most themes
# Question mark ? next to comment if not sure or can't find anywhere to scrape from
 
# Some descriptions:
# http://www.quimp.net/gamemaker/system-colors
# http://www.endolith.com/wordpress/2008/08/03/wine-colors/
# http://support.microsoft.com/kb/58336
# http://msdn.microsoft.com/en-us/library/system.drawing.systemcolors_properties(VS.80).aspx
 
# TitleText Active title bar text
# ActiveTitle Left end of active title bar
# GradientActiveTitle Right end of active title bar
# ActiveBorder Active window border
# InactiveTitleText Inactive title bar text
# InactiveTitle Left end of inactive title bar
# GradientInactiveTitle Right end of inactive title bar
# InactiveBorder Inactive window border
 
# AppWorkSpace Background color of multiple-document interface
# Background Desktop solid color
 
# ButtonText Button/tab text and glyphs
# ButtonHilight Outermost button higlight / Grayed-out button text shadow
# ButtonLight Inner button highlight, usually same as ButtonFace
# ButtonFace Background for buttons and all 3D objects
# ButtonAlternateFace ???
# ButtonShadow Shadows of buttons / Grayed-out button text
# ButtonDkShadow Outermost shadow of buttons
 
# GrayText Grayed out text in windows, like labels for unavailable widgets
# Hilight Background of selected text
# HilightText Selected text
# HotTrackingColor Single-click navigation hover color
 
# InfoText ToolTip text
# InfoWindow ToolTip background
 
# Menu Background for menus, also background for menu bars in 3D mode
# MenuBar Background for menu bars - rarely seen due to 3D menus
# MenuHilight Highlight for flat menus - in 3D mode, Hilight is used instead
# MenuText Menu text
 
# Scrollbar Background color of scrollbar, but only in some apps
# Window Background color of notepad, for instance
# WindowFrame Glow around focused widget
# WindowText Text in notepad, for instance
 
 
# These were all found by trial and error. Please point out any mistakes.
# TODO: Need to mark which colors do not work with which themes and double-check EVERYTHING
# * = Confirmed to work exactly for all themes (except Darklooks)
# + = Not perfect, but close?
# ? = Nothing to scrape? - Chose something similar
 
gtk_colors = {
 
# Title bars can't be accessed from PyGTK(?) so I just guessed to
# make it work reasonably well with themes like Human.
# Default Windows theme: Darker on left, light on right
'TitleText': window.style.white , #? White since we're guessing on dark selection color for titlebar
'InactiveTitleText': window.style.white , #? White since we're guessing on dark selection color for titlebar
'ActiveTitle': window.style.dark[gtk.STATE_SELECTED] , #? Guess on selection color like Clearlooks
'InactiveTitle': window.style.dark[gtk.STATE_NORMAL] , #? Darker color for gradient
'GradientActiveTitle': window.style.light[gtk.STATE_SELECTED], #? Lighter version for gradient
'GradientInactiveTitle': window.style.base[gtk.STATE_NORMAL] , #? Guess on base color
'ActiveBorder': button.style.bg[gtk.STATE_INSENSITIVE], #? Same as ButtonFace like Clearlooks
'InactiveBorder': button.style.bg[gtk.STATE_INSENSITIVE], #? Same as ButtonFace
 
'AppWorkSpace': window.style.base[gtk.STATE_NORMAL], #? MDI not used in GTK; use same color as Window, like Glade
'Background': None , #* Scraped from gconf below
 
'ButtonText': button.style.fg[gtk.STATE_NORMAL] , #*
'ButtonHilight': button.style.light[gtk.STATE_INSENSITIVE], #*
'ButtonLight': button.style.bg[gtk.STATE_INSENSITIVE] , #* Usually same as ButtonFace?
'ButtonFace': button.style.bg[gtk.STATE_INSENSITIVE] , #*
'ButtonAlternateFace': button.style.bg[gtk.STATE_INSENSITIVE] , #* Set to same as ButtonFace for now
'ButtonShadow': button.style.dark[gtk.STATE_INSENSITIVE] , #*
'ButtonDkShadow': button.style.black , #*
 
'GrayText': window.style.fg[gtk.STATE_INSENSITIVE], #*
'Hilight': window.style.base[gtk.STATE_SELECTED] , #*
'HilightText': window.style.fg[gtk.STATE_SELECTED] , #*
'HotTrackingColor': window.style.light[gtk.STATE_NORMAL] , #? Doesn't seem to exist in GTK; use lighter ButtonFace color, like CompizConfig Settings Manager
 
'InfoText': tooltip.style.fg[gtk.STATE_NORMAL],
'InfoWindow': tooltip.style.bg[gtk.STATE_NORMAL],
 
'Menu': menuitem.style.light[gtk.STATE_ACTIVE],
'MenuBar': menubar.style.bg[gtk.STATE_NORMAL] ,
'MenuHilight': menuitem.style.bg[gtk.STATE_SELECTED] ,
'MenuText': menuitem.style.fg[gtk.STATE_NORMAL] ,
 
'Scrollbar': scrollbar.style.bg[gtk.STATE_ACTIVE], #+ Not right, even though gtk.RcStyle documentation says it is
'Window': window.style.base[gtk.STATE_NORMAL] , #* base or bg?
'WindowFrame': button.style.mid[gtk.STATE_SELECTED], #+ bg selected or light selected?
'WindowText': window.style.text[gtk.STATE_NORMAL] , #*
}
 
# As far as I know, there is no way to programmatically extract colors from GTK for the same elements in any engine, so we'll have to add engine-specific scrapers.
# "Engines can and do whatever they want with the colors from the rc file ... A theme includes both the colors, and the code that paints using colors. So the code can use any of the colors it wants."
# TODO: something like this:
 
print "GTK engine:",
 
if 'ClearlooksStyle' in repr(window.style): # kludgy, but works
    print "Clearlooks"
    # assign different colors to some elements
elif 'MurrineStyle' in repr(window.style):
    print "Murrine"
    gtk_colors.update({'Window': window.style.base[gtk.STATE_NORMAL]})
elif 'CruxStyle' in repr(window.style):
    print "Crux"
else:
    print "unknown"
     
# QtPixbufStyle GlideStyle PixbufStyle HcStyle IndustrialStyle MistStyle ThiniceStyle darklooks = gtk.Style
 
 
 
# Create list of formatted color value pair strings
# Windows registry values are in the form "name"="data" with no spaces
color_pairs = []
for name, data in gtk_colors.iteritems():
    if data:
        color_pairs.append('"%s"="%s"' % (name, format_color_string(data)))
 
 
# Get Desktop background color from Gnome's GConf, append to color pair list
c = Client()
desktop_color = format_hex_color(c.get_value('/desktop/gnome/background/primary_color'))
if desktop_color:
    color_pairs.append('"Background"="%s"' % desktop_color)
 
# TODO: Get Desktop background color from Xfce
# import xfce4?
# "i see, yes xfce does have something like that. you find it in /home/$USER/.config/xfce4/mcs_settings/desktop.xml"
 
 
# Create a temporary Windows .reg registry file with the new values
# I'm not sure of the meaning of S-1-5-4. This may not work on all systems?
# I do know it is the same number under multiple accounts.
try:
    wineprefix = os.environ['WINEPREFIX']
except KeyError:
    wineprefix = os.path.join(os.environ['HOME'],'.wine')
winetemp = os.path.join(wineprefix, 'drive_c','windows','temp')
f = NamedTemporaryFile(prefix = 'winecolors', suffix = '.reg', dir = winetemp, mode = 'w+')
f.write("""REGEDIT4
 
[HKEY_USERS\S-1-5-4\Control Panel]
 
[HKEY_USERS\S-1-5-4\Control Panel\Colors]
""")
 
# Alphabetize list (purely so that user.reg is easy to read; Wine doesn't care)
color_pairs = sorted(color_pairs)
 
# Append list to file, with newlines
f.writelines(line + '\n' for line in color_pairs)
f.flush()
 
# Debugging
if debug_mode:
    print '---- [' + f.name + '] ----'
    f.seek(0)
    for line in f:
        print line,
    print '--------\n'
 
# Import values into Wine registry using regedit command
print('Using regedit to import colors into registry...\n')
os.system('regedit ' + f.name)
# TODO: Check if this worked correctly.
 
# Delete temporary file
f.close()
 
print('Done importing colors')
 
# TODO: catch errors from regedit not working?