-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #183 from thenaterhood/dev
* wayland gets custom cursors (#182) * wayland gets custom cursors * lint * lint * tests, lint * lint * fix custom cursor loop * cancel cursor locate on keypress * lint * specfile and readme * fix saving to nontransparent formats
- Loading branch information
Showing
14 changed files
with
275 additions
and
46 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
''' | ||
Interface class for integrating cursor locators | ||
''' | ||
import typing | ||
|
||
|
||
class CursorLocator(): | ||
'''Parent class for cursor locator strategies''' | ||
|
||
__utilityname__: str = "default" | ||
|
||
def __init__(self): | ||
"""constructor""" | ||
|
||
def get_cursor_position(self) -> typing.Optional[typing.Tuple[int, int]]: | ||
'''Return the cursor position as a tuple of (x, y)''' | ||
raise NotImplementedError() | ||
|
||
@staticmethod | ||
def can_run() -> bool: | ||
""" | ||
Whether this cursor locator can run | ||
""" | ||
return True |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
''' | ||
Utilities for selecting a cursor locator utility | ||
''' | ||
|
||
import typing | ||
from gscreenshot.cursor_locator import CursorLocator | ||
from gscreenshot.cursor_locator.gtk_cursor_locator import GtkCursorLocator | ||
from gscreenshot.cursor_locator.x11_cursor_locator import X11CursorLocator | ||
from gscreenshot.util import session_is_wayland | ||
|
||
|
||
class NoSupportedCursorLocatorError(Exception): | ||
"""NoSupportedCursorLocatorError""" | ||
|
||
|
||
class CursorLocatorFactory(object): | ||
'''Selects and instantiates a usable cursor finder''' | ||
|
||
def __init__(self, cursor_locator=None): | ||
self.cursor_locator:typing.Optional[CursorLocator] = cursor_locator | ||
self.xorg_locators = [ | ||
X11CursorLocator, | ||
GtkCursorLocator | ||
] | ||
|
||
self.wayland_locators = [ | ||
GtkCursorLocator | ||
] | ||
|
||
self.locators:list = [] | ||
|
||
if session_is_wayland(): | ||
self.locators = self.wayland_locators | ||
else: | ||
self.locators = self.xorg_locators | ||
|
||
def create(self) -> CursorLocator: | ||
'''Returns a locator instance''' | ||
if self.cursor_locator is not None: | ||
return self.cursor_locator | ||
|
||
for locator in self.locators: | ||
if locator.can_run(): | ||
return locator() | ||
|
||
raise NoSupportedCursorLocatorError( | ||
"No supported cursor locator available", | ||
[x.__utilityname__ for x in self.locators if x.__utilityname__ is not None] | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
''' | ||
Classes for capturing the cursor position using Gtk | ||
''' | ||
#pylint: disable=wrong-import-order | ||
#pylint: disable=wrong-import-position | ||
#pylint: disable=ungrouped-imports | ||
import typing | ||
import pygtkcompat | ||
pygtkcompat.enable() | ||
pygtkcompat.enable_gtk(version='3.0') | ||
|
||
from gi.repository import Gtk, Gdk | ||
from gscreenshot.cursor_locator import CursorLocator | ||
|
||
|
||
class GtkCursorLocator(CursorLocator): | ||
''' | ||
Interactive cursor locator driving class | ||
''' | ||
|
||
__utilityname__: str = "gscreenshot" | ||
|
||
def get_cursor_position(self) -> typing.Optional[typing.Tuple[int, int]]: | ||
""" | ||
Gets the current position of the mouse cursor, if able. | ||
Returns (x, y) or None. | ||
""" | ||
locator = GtkCursorLocatorWindow() | ||
locator.show_all() | ||
Gtk.main() | ||
while Gtk.events_pending(): | ||
Gtk.main_iteration() | ||
|
||
return locator.position | ||
@staticmethod | ||
def can_run() -> bool: | ||
return True | ||
|
||
|
||
class GtkCursorLocatorWindow(Gtk.Window): | ||
''' | ||
GTK window for capturing the cursor position | ||
''' | ||
def __init__(self): | ||
'''constructor''' | ||
self.position = None | ||
super().__init__() | ||
self.set_title("gscreenshot") | ||
self.set_position(Gtk.WindowPosition.CENTER) | ||
self.fullscreen() | ||
self.set_opacity(.65) | ||
self.screen = self.get_screen() | ||
|
||
box: Gtk.Grid = Gtk.Grid( | ||
vexpand=False, | ||
halign = Gtk.Align.CENTER, | ||
valign = Gtk.Align.CENTER | ||
) | ||
|
||
help_text = Gtk.Label() | ||
help_text.set_text( | ||
"Move your cursor to the desired position then click to capture" | ||
) | ||
help_subtext = Gtk.Label() | ||
help_subtext.set_text( | ||
"This extra step is required on Wayland. On X11, install Xlib to skip this." | ||
) | ||
box.attach(help_text, 0, 0, 1, 1) | ||
box.attach(help_subtext, 0, 1, 1, 1) | ||
self.add(box) | ||
self.connect("button_press_event", self.on_button_press) | ||
self.connect("key-press-event", self.on_keypress) | ||
|
||
self.set_events(Gdk.POINTER_MOTION_MASK | ||
| Gdk.BUTTON_PRESS_MASK) | ||
|
||
def on_button_press(self, _widget, event): | ||
'''handle button press''' | ||
self.position = (int(event.x), int(event.y)) | ||
self.destroy() | ||
Gtk.main_quit() | ||
|
||
def on_keypress(self, _widget, _event): | ||
'''handle keypress''' | ||
self.destroy() | ||
Gtk.main_quit() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
""" | ||
Xlib cursor locator classes | ||
""" | ||
import typing | ||
try: | ||
from Xlib import display | ||
except ImportError: | ||
display = None | ||
|
||
from gscreenshot.cursor_locator import CursorLocator | ||
|
||
|
||
class X11CursorLocator(CursorLocator): | ||
'''Xlib-based cursor locator''' | ||
|
||
__utilityname__: str = "python-xlib" | ||
|
||
def get_cursor_position(self) -> typing.Optional[typing.Tuple[int, int]]: | ||
""" | ||
Gets the current position of the mouse cursor, if able. | ||
Returns (x, y) or None. | ||
""" | ||
if display is None: | ||
return None | ||
|
||
try: | ||
# This is a ctype | ||
# pylint: disable=protected-access | ||
mouse_data = display.Display().screen().root.query_pointer()._data | ||
if 'root_x' not in mouse_data or 'root_y' not in mouse_data: | ||
return None | ||
# pylint: disable=bare-except | ||
except: | ||
# We don't really care about the specific error here. If we can't | ||
# get the pointer, then just move on. | ||
return None | ||
|
||
return (mouse_data["root_x"], mouse_data["root_y"]) | ||
|
||
@staticmethod | ||
def can_run() -> bool: | ||
'''can_run''' | ||
return display is not None |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.