1# -*- Mode: Python; py-indent-offset: 4 -*- 2# vim: tabstop=4 shiftwidth=4 expandtab 3# 4# Copyright (C) 2009 Johan Dahlin <johan@gnome.org> 5# 2010 Simon van der Linden <svdlinden@src.gnome.org> 6# 7# This library is free software; you can redistribute it and/or 8# modify it under the terms of the GNU Lesser General Public 9# License as published by the Free Software Foundation; either 10# version 2.1 of the License, or (at your option) any later version. 11# 12# This library is distributed in the hope that it will be useful, 13# but WITHOUT ANY WARRANTY; without even the implied warranty of 14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15# Lesser General Public License for more details. 16# 17# You should have received a copy of the GNU Lesser General Public 18# License along with this library; if not, write to the Free Software 19# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 20# USA 21 22import sys 23import warnings 24 25from ..overrides import override, strip_boolean_result 26from ..module import get_introspection_module 27from gi import PyGIDeprecationWarning, require_version 28 29Gdk = get_introspection_module('Gdk') 30GDK2 = Gdk._version == '2.0' 31GDK3 = Gdk._version == '3.0' 32 33__all__ = [] 34 35 36# https://bugzilla.gnome.org/show_bug.cgi?id=673396 37try: 38 require_version("GdkX11", Gdk._version) 39 from gi.repository import GdkX11 40 GdkX11 # pyflakes 41except (ValueError, ImportError): 42 pass 43 44if GDK2 or GDK3: 45 # Gdk.Color was deprecated since 3.14 and dropped in Gtk-4.0 46 class Color(Gdk.Color): 47 MAX_VALUE = 65535 48 49 def __init__(self, red, green, blue): 50 Gdk.Color.__init__(self) 51 self.red = red 52 self.green = green 53 self.blue = blue 54 55 def __eq__(self, other): 56 return self.equal(other) 57 58 def __repr__(self): 59 return 'Gdk.Color(red=%d, green=%d, blue=%d)' % (self.red, self.green, self.blue) 60 61 red_float = property(fget=lambda self: self.red / float(self.MAX_VALUE), 62 fset=lambda self, v: setattr(self, 'red', int(v * self.MAX_VALUE))) 63 64 green_float = property(fget=lambda self: self.green / float(self.MAX_VALUE), 65 fset=lambda self, v: setattr(self, 'green', int(v * self.MAX_VALUE))) 66 67 blue_float = property(fget=lambda self: self.blue / float(self.MAX_VALUE), 68 fset=lambda self, v: setattr(self, 'blue', int(v * self.MAX_VALUE))) 69 70 def to_floats(self): 71 """Return (red_float, green_float, blue_float) triple.""" 72 73 return (self.red_float, self.green_float, self.blue_float) 74 75 @staticmethod 76 def from_floats(red, green, blue): 77 """Return a new Color object from red/green/blue values from 0.0 to 1.0.""" 78 79 return Color(int(red * Color.MAX_VALUE), 80 int(green * Color.MAX_VALUE), 81 int(blue * Color.MAX_VALUE)) 82 83 Color = override(Color) 84 __all__.append('Color') 85 86if GDK3: 87 # Introduced since Gtk-3.0 88 class RGBA(Gdk.RGBA): 89 def __init__(self, red=1.0, green=1.0, blue=1.0, alpha=1.0): 90 Gdk.RGBA.__init__(self) 91 self.red = red 92 self.green = green 93 self.blue = blue 94 self.alpha = alpha 95 96 def __eq__(self, other): 97 return self.equal(other) 98 99 def __repr__(self): 100 return 'Gdk.RGBA(red=%f, green=%f, blue=%f, alpha=%f)' % (self.red, self.green, self.blue, self.alpha) 101 102 def __iter__(self): 103 """Iterator which allows easy conversion to tuple and list types.""" 104 105 yield self.red 106 yield self.green 107 yield self.blue 108 yield self.alpha 109 110 def to_color(self): 111 """Converts this RGBA into a Color instance which excludes alpha.""" 112 113 return Color(int(self.red * Color.MAX_VALUE), 114 int(self.green * Color.MAX_VALUE), 115 int(self.blue * Color.MAX_VALUE)) 116 117 @classmethod 118 def from_color(cls, color): 119 """Returns a new RGBA instance given a Color instance.""" 120 121 return cls(color.red_float, color.green_float, color.blue_float) 122 123 RGBA = override(RGBA) 124 __all__.append('RGBA') 125 126if GDK2: 127 class Rectangle(Gdk.Rectangle): 128 129 def __init__(self, x, y, width, height): 130 Gdk.Rectangle.__init__(self) 131 self.x = x 132 self.y = y 133 self.width = width 134 self.height = height 135 136 def __repr__(self): 137 return 'Gdk.Rectangle(x=%d, y=%d, width=%d, height=%d)' % (self.x, self.y, self.height, self.width) 138 139 Rectangle = override(Rectangle) 140 __all__.append('Rectangle') 141elif GDK3: 142 # Newer GTK/gobject-introspection (3.17.x) include GdkRectangle in the 143 # typelib. See https://bugzilla.gnome.org/show_bug.cgi?id=748832 and 144 # https://bugzilla.gnome.org/show_bug.cgi?id=748833 145 if not hasattr(Gdk, 'Rectangle'): 146 from gi.repository import cairo as _cairo 147 Rectangle = _cairo.RectangleInt 148 149 __all__.append('Rectangle') 150 else: 151 # https://bugzilla.gnome.org/show_bug.cgi?id=756364 152 # These methods used to be functions, keep aliases for backwards compat 153 rectangle_intersect = Gdk.Rectangle.intersect 154 rectangle_union = Gdk.Rectangle.union 155 156 __all__.append('rectangle_intersect') 157 __all__.append('rectangle_union') 158 159if GDK2: 160 class Drawable(Gdk.Drawable): 161 def cairo_create(self): 162 return Gdk.cairo_create(self) 163 164 Drawable = override(Drawable) 165 __all__.append('Drawable') 166elif GDK3: 167 class Window(Gdk.Window): 168 def __new__(cls, parent, attributes, attributes_mask): 169 # Gdk.Window had to be made abstract, 170 # this override allows using the standard constructor 171 return Gdk.Window.new(parent, attributes, attributes_mask) 172 173 def __init__(self, parent, attributes, attributes_mask): 174 pass 175 176 def cairo_create(self): 177 return Gdk.cairo_create(self) 178 179 Window = override(Window) 180 __all__.append('Window') 181 182if GDK2 or GDK3: 183 Gdk.EventType._2BUTTON_PRESS = getattr(Gdk.EventType, "2BUTTON_PRESS") 184 Gdk.EventType._3BUTTON_PRESS = getattr(Gdk.EventType, "3BUTTON_PRESS") 185 186 class Event(Gdk.Event): 187 _UNION_MEMBERS = { 188 Gdk.EventType.DELETE: 'any', 189 Gdk.EventType.DESTROY: 'any', 190 Gdk.EventType.MOTION_NOTIFY: 'motion', 191 Gdk.EventType.BUTTON_PRESS: 'button', 192 Gdk.EventType.BUTTON_RELEASE: 'button', 193 Gdk.EventType.KEY_PRESS: 'key', 194 Gdk.EventType.KEY_RELEASE: 'key', 195 Gdk.EventType.ENTER_NOTIFY: 'crossing', 196 Gdk.EventType.LEAVE_NOTIFY: 'crossing', 197 Gdk.EventType.FOCUS_CHANGE: 'focus_change', 198 Gdk.EventType.CONFIGURE: 'configure', 199 Gdk.EventType.PROXIMITY_IN: 'proximity', 200 Gdk.EventType.PROXIMITY_OUT: 'proximity', 201 Gdk.EventType.DRAG_ENTER: 'dnd', 202 Gdk.EventType.DRAG_LEAVE: 'dnd', 203 Gdk.EventType.DRAG_MOTION: 'dnd', 204 Gdk.EventType.DROP_START: 'dnd', 205 Gdk.EventType._2BUTTON_PRESS: 'button', 206 Gdk.EventType._3BUTTON_PRESS: 'button', 207 Gdk.EventType.PROPERTY_NOTIFY: 'property', 208 Gdk.EventType.SELECTION_CLEAR: 'selection', 209 Gdk.EventType.SELECTION_REQUEST: 'selection', 210 Gdk.EventType.SELECTION_NOTIFY: 'selection', 211 Gdk.EventType.DRAG_STATUS: 'dnd', 212 Gdk.EventType.DROP_FINISHED: 'dnd', 213 Gdk.EventType.CLIENT_EVENT: 'client', 214 Gdk.EventType.VISIBILITY_NOTIFY: 'visibility', 215 Gdk.EventType.SCROLL: 'scroll', 216 Gdk.EventType.EXPOSE: 'expose', 217 Gdk.EventType.MAP: 'any', 218 Gdk.EventType.UNMAP: 'any', 219 } 220 221 if GDK2: 222 _UNION_MEMBERS[Gdk.EventType.NO_EXPOSE] = 'no_expose' 223 224 if hasattr(Gdk.EventType, 'TOUCH_BEGIN'): 225 _UNION_MEMBERS.update( 226 { 227 Gdk.EventType.TOUCH_BEGIN: 'touch', 228 Gdk.EventType.TOUCH_UPDATE: 'touch', 229 Gdk.EventType.TOUCH_END: 'touch', 230 Gdk.EventType.TOUCH_CANCEL: 'touch', 231 }) 232 233 def __getattr__(self, name): 234 real_event = getattr(self, '_UNION_MEMBERS').get(self.type) 235 if real_event: 236 return getattr(getattr(self, real_event), name) 237 else: 238 raise AttributeError("'%s' object has no attribute '%s'" % (self.__class__.__name__, name)) 239 240 def __setattr__(self, name, value): 241 real_event = getattr(self, '_UNION_MEMBERS').get(self.type) 242 if real_event: 243 setattr(getattr(self, real_event), name, value) 244 else: 245 Gdk.Event.__setattr__(self, name, value) 246 247 def __repr__(self): 248 base_repr = Gdk.Event.__repr__(self).strip("><") 249 return "<%s type=%r>" % (base_repr, self.type) 250 251 Event = override(Event) 252 __all__.append('Event') 253 254 # manually bind GdkEvent members to GdkEvent 255 256 modname = globals()['__name__'] 257 module = sys.modules[modname] 258 259 # right now we can't get the type_info from the 260 # field info so manually list the class names 261 event_member_classes = ['EventAny', 262 'EventExpose', 263 'EventMotion', 264 'EventButton', 265 'EventScroll', 266 'EventKey', 267 'EventCrossing', 268 'EventFocus', 269 'EventConfigure', 270 'EventProximity', 271 'EventDND', 272 'EventSetting', 273 'EventGrabBroken', 274 'EventVisibility', 275 'EventProperty', 276 'EventSelection', 277 'EventOwnerChange', 278 'EventWindowState', 279 'EventVisibility'] 280 281 if Gdk._version == '2.0': 282 event_member_classes.append('EventNoExpose') 283 284 if hasattr(Gdk, 'EventTouch'): 285 event_member_classes.append('EventTouch') 286 287 # whitelist all methods that have a success return we want to mask 288 gsuccess_mask_funcs = ['get_state', 289 'get_axis', 290 'get_coords', 291 'get_root_coords'] 292 293 for event_class in event_member_classes: 294 override_class = type(event_class, (getattr(Gdk, event_class),), {}) 295 # add the event methods 296 for method_info in Gdk.Event.__info__.get_methods(): 297 name = method_info.get_name() 298 event_method = getattr(Gdk.Event, name) 299 300 # use the _gsuccess_mask decorator if this method is whitelisted 301 if name in gsuccess_mask_funcs: 302 event_method = strip_boolean_result(event_method) 303 setattr(override_class, name, event_method) 304 305 setattr(module, event_class, override_class) 306 __all__.append(event_class) 307 308 # end GdkEvent overrides 309 310 class DragContext(Gdk.DragContext): 311 def finish(self, success, del_, time): 312 Gtk = get_introspection_module('Gtk') 313 Gtk.drag_finish(self, success, del_, time) 314 315 DragContext = override(DragContext) 316 __all__.append('DragContext') 317 318 class Cursor(Gdk.Cursor): 319 320 def __new__(cls, *args, **kwds): 321 arg_len = len(args) 322 kwd_len = len(kwds) 323 total_len = arg_len + kwd_len 324 325 if total_len == 1: 326 # Since g_object_newv (super.__new__) does not seem valid for 327 # direct use with GdkCursor, we must assume usage of at least 328 # one of the C constructors to be valid. 329 return cls.new(*args, **kwds) 330 331 elif total_len == 2: 332 warnings.warn('Calling "Gdk.Cursor(display, cursor_type)" has been deprecated. ' 333 'Please use Gdk.Cursor.new_for_display(display, cursor_type). ' 334 'See: https://wiki.gnome.org/PyGObject/InitializerDeprecations', 335 PyGIDeprecationWarning) 336 return cls.new_for_display(*args, **kwds) 337 338 elif total_len == 4: 339 warnings.warn('Calling "Gdk.Cursor(display, pixbuf, x, y)" has been deprecated. ' 340 'Please use Gdk.Cursor.new_from_pixbuf(display, pixbuf, x, y). ' 341 'See: https://wiki.gnome.org/PyGObject/InitializerDeprecations', 342 PyGIDeprecationWarning) 343 return cls.new_from_pixbuf(*args, **kwds) 344 345 elif total_len == 6: 346 if not GDK2: 347 # pixmaps don't exist in Gdk 3.0 348 raise ValueError("Wrong number of parameters") 349 350 warnings.warn('Calling "Gdk.Cursor(source, mask, fg, bg, x, y)" has been deprecated. ' 351 'Please use Gdk.Cursor.new_from_pixmap(source, mask, fg, bg, x, y). ' 352 'See: https://wiki.gnome.org/PyGObject/InitializerDeprecations', 353 PyGIDeprecationWarning) 354 return cls.new_from_pixmap(*args, **kwds) 355 356 else: 357 raise ValueError("Wrong number of parameters") 358 359 Cursor = override(Cursor) 360 __all__.append('Cursor') 361 362 # Gdk.Color was deprecated since 3.14 and dropped in Gtk-4.0 363 color_parse = strip_boolean_result(Gdk.color_parse) 364 __all__.append('color_parse') 365 366 # Note, we cannot override the entire class as Gdk.Atom has no gtype, so just 367 # hack some individual methods 368 def _gdk_atom_str(atom): 369 n = atom.name() 370 if n: 371 return n 372 # fall back to atom index 373 return 'Gdk.Atom<%i>' % hash(atom) 374 375 def _gdk_atom_repr(atom): 376 n = atom.name() 377 if n: 378 return 'Gdk.Atom.intern("%s", False)' % n 379 # fall back to atom index 380 return '<Gdk.Atom(%i)>' % hash(atom) 381 382 Gdk.Atom.__str__ = _gdk_atom_str 383 Gdk.Atom.__repr__ = _gdk_atom_repr 384 385 386# constants 387if GDK3: 388 SELECTION_PRIMARY = Gdk.atom_intern('PRIMARY', True) 389 __all__.append('SELECTION_PRIMARY') 390 391 SELECTION_SECONDARY = Gdk.atom_intern('SECONDARY', True) 392 __all__.append('SELECTION_SECONDARY') 393 394 SELECTION_CLIPBOARD = Gdk.atom_intern('CLIPBOARD', True) 395 __all__.append('SELECTION_CLIPBOARD') 396 397 TARGET_BITMAP = Gdk.atom_intern('BITMAP', True) 398 __all__.append('TARGET_BITMAP') 399 400 TARGET_COLORMAP = Gdk.atom_intern('COLORMAP', True) 401 __all__.append('TARGET_COLORMAP') 402 403 TARGET_DRAWABLE = Gdk.atom_intern('DRAWABLE', True) 404 __all__.append('TARGET_DRAWABLE') 405 406 TARGET_PIXMAP = Gdk.atom_intern('PIXMAP', True) 407 __all__.append('TARGET_PIXMAP') 408 409 TARGET_STRING = Gdk.atom_intern('STRING', True) 410 __all__.append('TARGET_STRING') 411 412 SELECTION_TYPE_ATOM = Gdk.atom_intern('ATOM', True) 413 __all__.append('SELECTION_TYPE_ATOM') 414 415 SELECTION_TYPE_BITMAP = Gdk.atom_intern('BITMAP', True) 416 __all__.append('SELECTION_TYPE_BITMAP') 417 418 SELECTION_TYPE_COLORMAP = Gdk.atom_intern('COLORMAP', True) 419 __all__.append('SELECTION_TYPE_COLORMAP') 420 421 SELECTION_TYPE_DRAWABLE = Gdk.atom_intern('DRAWABLE', True) 422 __all__.append('SELECTION_TYPE_DRAWABLE') 423 424 SELECTION_TYPE_INTEGER = Gdk.atom_intern('INTEGER', True) 425 __all__.append('SELECTION_TYPE_INTEGER') 426 427 SELECTION_TYPE_PIXMAP = Gdk.atom_intern('PIXMAP', True) 428 __all__.append('SELECTION_TYPE_PIXMAP') 429 430 SELECTION_TYPE_WINDOW = Gdk.atom_intern('WINDOW', True) 431 __all__.append('SELECTION_TYPE_WINDOW') 432 433 SELECTION_TYPE_STRING = Gdk.atom_intern('STRING', True) 434 __all__.append('SELECTION_TYPE_STRING') 435 436if GDK2 or GDK3: 437 import sys 438 initialized, argv = Gdk.init_check(sys.argv) 439