#!/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()

# Mappings for all the color values (described in readme.txt)
# 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?