A set of tools for configuring the Logitech G19 keyboard. Based in: https://github.com/Gnome15/gnome15
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

287 lines
10 KiB

# Gnome15 - Suite of tools for the Logitech G series keyboards and headsets
# Copyright (C) 2010 Brett Smith <tanktarta@blueyonder.co.uk>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
'''
A top level GTK windows that draws on the LCD
'''
import gtk
import gobject
import g15driver
import util.g15cairo as g15cairo
import util.g15pythonlang as g15pythonlang
from threading import Lock
from threading import Semaphore
import g15theme
import g15screen
import cairo
import ctypes
_initialized = False
def create_cairo_font_face_for_file (filename, faceindex=0, loadoptions=0):
global _initialized
global _freetype_so
global _cairo_so
global _ft_lib
global _surface
CAIRO_STATUS_SUCCESS = 0
FT_Err_Ok = 0
if not _initialized:
# find shared objects
_freetype_so = ctypes.CDLL ("libfreetype.so.6")
_cairo_so = ctypes.CDLL ("libcairo.so.2")
_cairo_so.cairo_ft_font_face_create_for_ft_face.restype = ctypes.c_void_p
_cairo_so.cairo_ft_font_face_create_for_ft_face.argtypes = [ ctypes.c_void_p, ctypes.c_int ]
_cairo_so.cairo_set_font_face.argtypes = [ ctypes.c_void_p, ctypes.c_void_p ]
_cairo_so.cairo_font_face_status.argtypes = [ ctypes.c_void_p ]
_cairo_so.cairo_status.argtypes = [ ctypes.c_void_p ]
# initialize freetype
_ft_lib = ctypes.c_void_p ()
if FT_Err_Ok != _freetype_so.FT_Init_FreeType (ctypes.byref (_ft_lib)):
raise "Error initialising FreeType library."
class PycairoContext(ctypes.Structure):
_fields_ = [("PyObject_HEAD", ctypes.c_byte * object.__basicsize__),
("ctx", ctypes.c_void_p),
("base", ctypes.c_void_p)]
_surface = cairo.ImageSurface (cairo.FORMAT_A8, 0, 0)
_initialized = True
# create freetype face
ft_face = ctypes.c_void_p()
cairo_ctx = cairo.Context (_surface)
cairo_t = PycairoContext.from_address(id(cairo_ctx)).ctx
if FT_Err_Ok != _freetype_so.FT_New_Face (_ft_lib, filename, faceindex, ctypes.byref(ft_face)):
raise Exception("Error creating FreeType font face for " + filename)
# create cairo font face for freetype face
cr_face = _cairo_so.cairo_ft_font_face_create_for_ft_face (ft_face, loadoptions)
if CAIRO_STATUS_SUCCESS != _cairo_so.cairo_font_face_status (cr_face):
raise Exception("Error creating cairo font face for " + filename)
_cairo_so.cairo_set_font_face (cairo_t, cr_face)
if CAIRO_STATUS_SUCCESS != _cairo_so.cairo_status (cairo_t):
raise Exception("Error creating cairo font face for " + filename)
face = cairo_ctx.get_font_face ()
return face
class G15OffscreenWindow(g15theme.Component):
def __init__(self, component_id):
g15theme.Component.__init__(self, component_id)
self.window = None
self.content = None
def on_configure(self):
g15theme.Component.on_configure(self)
gobject.idle_add(self._create_window)
self.get_screen().key_handler.action_listeners.append(self)
def notify_remove(self):
g15theme.Component.notify_remove(self)
self.get_screen().key_handler.action_listeners.remove(self)
def set_content(self, content):
self.content = content
if self.window is not None:
gobject.idle_add(self._do_set_content)
def action_performed(self, binding):
if self.is_visible():
if binding.action == g15driver.NEXT_SELECTION:
gobject.idle_add(self.window.focus_next)
elif binding.action == g15driver.PREVIOUS_SELECTION:
gobject.idle_add(self.window.focus_previous)
if binding.action == g15driver.NEXT_PAGE:
gobject.idle_add(self.window.change_widget)
elif binding.action == g15driver.PREVIOUS_PAGE:
gobject.idle_add(self.window.change_widget, None, True)
elif binding.action == g15driver.SELECT:
pass
def paint(self, canvas):
g15theme.Component.paint(self, canvas)
if self.window is not None:
self.window.paint(canvas)
"""
Private
"""
def _do_set_content(self):
self.window.set_content(self.content)
def _create_window(self):
screen = self.get_screen()
window = G15Window(screen, self.get_root(), self.view_bounds[0], self.view_bounds[1], \
self.view_bounds[2], self.view_bounds[3])
if self.content is not None:
self.window.set_content(self.content)
self.window = window
screen.redraw(self.get_root())
class G15Window(gtk.OffscreenWindow):
def __init__(self, screen, page, area_x, area_y, area_width, area_height):
gtk.OffscreenWindow.__init__(self)
self.pixbuf = None
self.scroller = None
self.screen = screen
self.page = page
self.lock = None
self.area_x = int(area_x)
self.area_y = int(area_y)
self.area_width = int(area_width)
self.area_height = int(area_height)
self.surface = None
self.content = gtk.EventBox()
self.set_app_paintable(True)
self.content.set_app_paintable(True)
self.connect("screen-changed", self.screen_changed)
self.content.connect("expose-event", self._transparent_expose)
self.content.set_size_request(self.area_width, self.area_height)
self.add(self.content)
self.connect("damage_event", self._damage)
self.connect("expose_event", self._expose)
self.screen_changed(None, None)
self.lock = Semaphore()
def set_content(self, content):
self.content.add(content)
self.show_all()
# If the content window is a scroller, we send focus events to it
# moving the scroller position to the focussed component
if isinstance(content, gtk.ScrolledWindow):
self.scroller = content
def paint(self, canvas):
if g15pythonlang.is_gobject_thread():
raise Exception("Painting on mainloop")
self.start_for_capture()
gobject.idle_add(self._do_capture)
self.lock.acquire()
canvas.save()
canvas.translate(self.area_x, self.area_y)
canvas.set_source_surface(self.surface)
canvas.paint()
canvas.restore()
def focus_next(self):
self.content.get_toplevel().child_focus(gtk.DIR_TAB_FORWARD)
self.scroll_to_focussed()
self.screen.redraw(self.page)
def focus_previous(self):
self.content.get_toplevel().child_focus(gtk.DIR_TAB_BACKWARD)
self.screen.redraw(self.page)
self.scroll_to_focussed()
def change_widget(self, amount = None, reverse = False):
focussed = self.get_focus()
if focussed != None:
if isinstance(focussed, gtk.HScale):
adj = focussed.get_adjustment()
ps = adj.get_page_size() if amount is None else amount
if ps == 0:
ps = 10
if reverse:
adj.set_value(adj.get_value() - ps)
else:
adj.set_value(adj.get_value() + ps)
self.screen.redraw(self.page)
def show_all(self):
gtk.OffscreenWindow.show_all(self)
def scroll_to_focussed(self):
if self.scroller is not None:
hadj = self.scroller.get_hadjustment()
vadj = self.scroller.get_vadjustment()
x, y = self.get_focus().translate_coordinates(self.scroller.get_children()[0], 0, 0)
max_x = hadj.upper - hadj.page_size
max_y = vadj.upper - vadj.page_size
hadj.set_value(min(x, max_x))
vadj.set_value(min(y, max_y))
def screen_changed(self, widget, old_screen=None):
global supports_alpha
# To check if the display supports alpha channels, get the colormap
screen = self.get_screen()
colormap = screen.get_rgba_colormap()
if colormap == None:
colormap = screen.get_rgb_colormap()
supports_alpha = False
else:
supports_alpha = True
# Now we have a colormap appropriate for the screen, use it
self.set_colormap(colormap)
return False
def _transparent_expose(self, widget, event = None):
"""
To overcome inability to set a container component as transparent. I
cannot get compositing working (perhaps it just doesn't because we are
going to an offscreen window). So, to get pseudo-transparency,
we repaint the background the screen would normally paint, offset by
the position of this component
"""
cr = widget.window.cairo_create()
self.screen.clear_canvas(cr)
cr.save()
cr.translate(-self.area_x, -self.area_y)
for s in self.screen.painters:
if s.place == g15screen.BACKGROUND_PAINTER:
s.paint(cr)
cr.restore()
return False
def _expose(self, widget, event):
self.screen.redraw(self.page)
return False
def _damage(self, widget, event):
# print "Damage"
# self.screen.redraw(self.page)
return False
def start_for_capture(self):
self.lock = Lock()
self.lock.acquire()
def _do_capture(self):
self.content.window.invalidate_rect((0,0,self.area_width,self.area_height), True)
self.content.window.process_updates(True)
pixbuf = gtk.gdk.Pixbuf( gtk.gdk.COLORSPACE_RGB, False, 8, self.area_width, self.area_height)
pixbuf.get_from_drawable(self.content.window, self.content.get_colormap(), 0, 0, 0, 0, self.area_width, self.area_height)
self.surface = g15cairo.pixbuf_to_surface(pixbuf)
self.pixbuf = pixbuf
self.lock.release()