wine_colors_from_gtk.py 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. #!/usr/bin/env python
  2. # Scrape colors from GTK and import them into Wine through the registry
  3. #
  4. # endolith@gmail.com 2009-02-06
  5. #
  6. # Based on script by KillerKiwi [Ubuntu Forums] October 29th, 2007
  7. # http://ubuntuforums.org/showthread.php?t=55286&page=3#23
  8. #
  9. # which is based on patch by Johannes Roith [Mono-winforms-list] Wed, 27 Aug 2003
  10. # http://lists.ximian.com/pipermail/mono-winforms-list/2003-August/000469.html
  11. import pygtk
  12. import gtk
  13. import os
  14. from tempfile import NamedTemporaryFile
  15. from gconf import Client
  16. import re
  17. # TODO: command line switch
  18. debug_mode = False
  19. def format_color_string(Color):
  20. """ Convert 48-bit gdk.Color to 24-bit 'RRR GGG BBB' triple. """
  21. if type(Color) is gtk.gdk.Color:
  22. return '%s %s %s' % (Color.red/256, Color.green/256, Color.blue/256)
  23. else:
  24. print('Not a GdkColor: ' + str(Color))
  25. return None
  26. def format_hex_color(color):
  27. """ Convert from hex color string to decimal 'RRR GGG BBB' triple. """
  28. if re.match('^#[0-9a-fA-F]{12}$', color):
  29. r, g, b = color[1:3], color[5:7], color[9:11] #rrrrggggbbbb
  30. elif re.match('^#[0-9a-fA-F]{6}$', color):
  31. r, g, b = color[1:3], color[3:5], color[5:7] #RRGGBB
  32. elif re.match('^#[0-9a-fA-F]{3}$', color):
  33. r, g, b = color[1]*2, color[2]*2, color[3]*2 #09C becomes 0099CC.
  34. else:
  35. print('Cannot understand color string format: ' + str(color))
  36. return None
  37. return '%s %s %s' % (int(r,16), int(g,16), int(b,16))
  38. # TODO: fonts
  39. # Get some colors from GTK
  40. # gtk.Style object:
  41. # http://www.moeraki.com/pygtkreference/pygtk2reference/class-gtkstyle.html
  42. # Create a window to scrape colors from
  43. window = gtk.Window()
  44. button = gtk.Button()
  45. vbox = gtk.VBox()
  46. vbox.add(button)
  47. scrollbar = gtk.VScrollbar()
  48. vbox.add(scrollbar)
  49. menubar = gtk.MenuBar()
  50. menuitem = gtk.MenuItem()
  51. menubar.add(menuitem)
  52. vbox.add(menubar)
  53. window.add(vbox)
  54. # On show_all(), these are all converted from gtk.Style objects with wrong
  55. # colors into __main__.EngineStyle objects with correct colors.
  56. window.show_all()
  57. # Tooltips
  58. # http://www.daa.com.au/pipermail/pygtk/2005-November/011353.html
  59. tooltip = gtk.Window()
  60. tooltip.set_name('gtk-tooltips')
  61. tooltip.show_all()
  62. # Mappings for all the color values (described in readme.txt)
  63. # TODO: Need to mark which colors do not work with which themes and double-check EVERYTHING
  64. # * = Confirmed to work exactly for all themes (except Darklooks)
  65. # + = Not perfect, but close?
  66. # ? = Nothing to scrape? - Chose something similar
  67. gtk_colors = {
  68. # Title bars can't be accessed from PyGTK(?) so I just guessed to
  69. # make it work reasonably well with themes like Human.
  70. # Default Windows theme: Darker on left, light on right
  71. 'TitleText': window.style.white , #? White since we're guessing on dark selection color for titlebar
  72. 'InactiveTitleText': window.style.white , #? White since we're guessing on dark selection color for titlebar
  73. 'ActiveTitle': window.style.dark[gtk.STATE_SELECTED] , #? Guess on selection color like Clearlooks
  74. 'InactiveTitle': window.style.dark[gtk.STATE_NORMAL] , #? Darker color for gradient
  75. 'GradientActiveTitle': window.style.light[gtk.STATE_SELECTED], #? Lighter version for gradient
  76. 'GradientInactiveTitle': window.style.base[gtk.STATE_NORMAL] , #? Guess on base color
  77. 'ActiveBorder': button.style.bg[gtk.STATE_INSENSITIVE], #? Same as ButtonFace like Clearlooks
  78. 'InactiveBorder': button.style.bg[gtk.STATE_INSENSITIVE], #? Same as ButtonFace
  79. 'AppWorkSpace': window.style.base[gtk.STATE_NORMAL], #? MDI not used in GTK; use same color as Window, like Glade
  80. 'Background': None , #* Scraped from gconf below
  81. 'ButtonText': button.style.fg[gtk.STATE_NORMAL] , #*
  82. 'ButtonHilight': button.style.light[gtk.STATE_INSENSITIVE], #*
  83. 'ButtonLight': button.style.bg[gtk.STATE_INSENSITIVE] , #* Usually same as ButtonFace?
  84. 'ButtonFace': button.style.bg[gtk.STATE_INSENSITIVE] , #*
  85. 'ButtonAlternateFace': button.style.bg[gtk.STATE_INSENSITIVE] , #* Set to same as ButtonFace for now
  86. 'ButtonShadow': button.style.dark[gtk.STATE_INSENSITIVE] , #*
  87. 'ButtonDkShadow': button.style.black , #*
  88. 'GrayText': window.style.fg[gtk.STATE_INSENSITIVE], #*
  89. 'Hilight': window.style.base[gtk.STATE_SELECTED] , #*
  90. 'HilightText': window.style.fg[gtk.STATE_SELECTED] , #*
  91. 'HotTrackingColor': window.style.light[gtk.STATE_NORMAL] , #? Doesn't seem to exist in GTK; use lighter ButtonFace color, like CompizConfig Settings Manager
  92. 'InfoText': tooltip.style.fg[gtk.STATE_NORMAL],
  93. 'InfoWindow': tooltip.style.bg[gtk.STATE_NORMAL],
  94. 'Menu': menuitem.style.light[gtk.STATE_ACTIVE],
  95. 'MenuBar': menubar.style.bg[gtk.STATE_NORMAL] ,
  96. 'MenuHilight': menuitem.style.bg[gtk.STATE_SELECTED] ,
  97. 'MenuText': menuitem.style.fg[gtk.STATE_NORMAL] ,
  98. 'Scrollbar': scrollbar.style.bg[gtk.STATE_ACTIVE], #+ Not right, even though gtk.RcStyle documentation says it is
  99. 'Window': window.style.base[gtk.STATE_NORMAL] , #* base or bg?
  100. 'WindowFrame': button.style.mid[gtk.STATE_SELECTED], #+ bg selected or light selected?
  101. 'WindowText': window.style.text[gtk.STATE_NORMAL] , #*
  102. }
  103. # 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.
  104. # "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."
  105. # TODO: something like this:
  106. print "GTK engine:",
  107. if 'ClearlooksStyle' in repr(window.style): # kludgy, but works
  108. print "Clearlooks"
  109. # assign different colors to some elements
  110. elif 'MurrineStyle' in repr(window.style):
  111. print "Murrine"
  112. gtk_colors.update({'Window': window.style.base[gtk.STATE_NORMAL]})
  113. elif 'CruxStyle' in repr(window.style):
  114. print "Crux"
  115. else:
  116. print "unknown"
  117. # QtPixbufStyle GlideStyle PixbufStyle HcStyle IndustrialStyle MistStyle ThiniceStyle darklooks = gtk.Style
  118. # Create list of formatted color value pair strings
  119. # Windows registry values are in the form "name"="data" with no spaces
  120. color_pairs = []
  121. for name, data in gtk_colors.iteritems():
  122. if data:
  123. color_pairs.append('"%s"="%s"' % (name, format_color_string(data)))
  124. # Get Desktop background color from Gnome's GConf, append to color pair list
  125. c = Client()
  126. desktop_color = format_hex_color(c.get_value('/desktop/gnome/background/primary_color'))
  127. if desktop_color:
  128. color_pairs.append('"Background"="%s"' % desktop_color)
  129. # TODO: Get Desktop background color from Xfce
  130. # import xfce4?
  131. # "i see, yes xfce does have something like that. you find it in /home/$USER/.config/xfce4/mcs_settings/desktop.xml"
  132. # Create a temporary Windows .reg registry file with the new values
  133. # I'm not sure of the meaning of S-1-5-4. This may not work on all systems?
  134. # I do know it is the same number under multiple accounts.
  135. try:
  136. wineprefix = os.environ['WINEPREFIX']
  137. except KeyError:
  138. wineprefix = os.path.join(os.environ['HOME'],'.wine')
  139. winetemp = os.path.join(wineprefix, 'drive_c','windows','temp')
  140. f = NamedTemporaryFile(prefix = 'winecolors', suffix = '.reg', dir = winetemp, mode = 'w+')
  141. f.write("""REGEDIT4
  142. [HKEY_USERS\S-1-5-4\Control Panel]
  143. [HKEY_USERS\S-1-5-4\Control Panel\Colors]
  144. """)
  145. # Alphabetize list (purely so that user.reg is easy to read; Wine doesn't care)
  146. color_pairs = sorted(color_pairs)
  147. # Append list to file, with newlines
  148. f.writelines(line + '\n' for line in color_pairs)
  149. f.flush()
  150. # Debugging
  151. if debug_mode:
  152. print '---- [' + f.name + '] ----'
  153. f.seek(0)
  154. for line in f:
  155. print line,
  156. print '--------\n'
  157. # Import values into Wine registry using regedit command
  158. print('Using regedit to import colors into registry...\n')
  159. os.system('regedit ' + f.name)
  160. # TODO: Check if this worked correctly.
  161. # Delete temporary file
  162. f.close()
  163. print('Done importing colors')
  164. # TODO: catch errors from regedit not working?