Exemplo n.º 1
0
    def __init__(self, profile_file):
        if not wpproc.RESOLUTION_ARRAY:
            msg = "Cannot parse profile, monitor resolution data is missing."
            show_message_dialog(msg)
            sp_logging.G_LOGGER(msg)
            exit()

        self.file = profile_file
        self.name = "default_profile"
        self.spanmode = "single"  # single / multi
        self.slideshow = True
        self.delay_list = [600]
        self.sortmode = "shuffle"  # shuffle ( random , sorted? )
        self.ppimode = False
        self.ppi_array = wpproc.NUM_DISPLAYS * [100]
        self.ppi_array_relative_density = []
        self.inches = []
        self.manual_offsets = wpproc.NUM_DISPLAYS * [(0, 0)]
        self.manual_offsets_useronly = []
        self.bezels = []
        self.bezel_px_offsets = []
        self.hk_binding = None
        self.paths_array = []

        self.parse_profile(self.file)
        if self.ppimode is True:
            self.compute_relative_densities()
            if self.bezels:
                self.compute_bezel_px_offsets()
        self.file_handler = self.Filehandler(self.paths_array, self.sortmode)
Exemplo n.º 2
0
        def __init__(self, paths_array, sortmode):
            # A list of lists if there is more than one monitor with distinct
            # input paths.
            self.all_files_in_paths = []
            self.paths_array = paths_array
            self.sortmode = sortmode
            for paths_list in paths_array:
                list_of_images = []
                for path in paths_list:
                    # Add list items to the end of the list instead of
                    # appending the list to the list.
                    if not os.path.exists(path):
                        message = "A path was not found: '{}'.\n\
Use absolute paths for best reliabilty.".format(path)
                        sp_logging.G_LOGGER.info(message)
                        show_message_dialog(message, "Error")
                        continue
                    else:
                        # List only images that are of supported type.
                        list_of_images += [
                            os.path.join(path, f) for f in os.listdir(path)
                            if f.endswith(wpproc.G_SUPPORTED_IMAGE_EXTENSIONS)
                        ]
                # Append the list of monitor_i specific files to the list of
                # lists of images.
                self.all_files_in_paths.append(list_of_images)
            self.iterators = []
            for diplay_image_list in self.all_files_in_paths:
                self.iterators.append(
                    self.ImageList(diplay_image_list, self.sortmode))
Exemplo n.º 3
0
    def read_general_settings(self):
        """Refreshes general settings from file and applies hotkey bindings."""
        self.g_settings = GeneralSettingsData()
        self.register_hotkeys()
        msg = "New settings are applied after an application restart. \
New hotkeys are registered."

        show_message_dialog(msg, "Info")
Exemplo n.º 4
0
 def read_general_settings(self):
     """Refreshes general settings from file and applies hotkey bindings."""
     self.g_settings = GeneralSettingsData()
     try:
         self.seen_binding
     except NameError:
         self.seen_binding = set()
     self.register_hotkeys()
     if self.g_settings.logging:
         msg = "Logging is enabled after an application restart."
         show_message_dialog(msg, "Info")
Exemplo n.º 5
0
 def is_list_valid_paths(self, input_list):
     """Verifies that input list contains paths and that they're valid."""
     if input_list == [""]:
         msg = "At least one path for wallpapers must be given."
         show_message_dialog(msg, "Error")
         return False
     if "" in input_list:
         msg = "Take care not to save a profile with an empty display paths field."
         show_message_dialog(msg, "Error")
         return False
     for path_list_str in input_list:
         path_list = path_list_str.split(";")
         for path in path_list:
             if os.path.isdir(path) is True:
                 supported_files = [
                     f for f in os.listdir(path)
                     if f.endswith(wpproc.G_SUPPORTED_IMAGE_EXTENSIONS)
                 ]
                 if supported_files:
                     continue
                 else:
                     msg = "Path '{}' does not contain supported image files.".format(
                         path)
                     show_message_dialog(msg, "Error")
                     return False
             else:
                 msg = "Path '{}' was not recognized as a directory.".format(
                     path)
                 show_message_dialog(msg, "Error")
                 return False
     valid_pathsarray = True
     return valid_pathsarray
Exemplo n.º 6
0
def list_profiles():
    """Lists profiles as initiated objects from the sp_paths.PROFILES_PATH."""
    files = sorted(os.listdir(sp_paths.PROFILES_PATH))
    profile_list = []
    for pfle in files:
        try:
            if pfle.endswith(".profile"):
                profile_list.append(
                    ProfileData(os.path.join(sp_paths.PROFILES_PATH, pfle)))
        except Exception as exep:  # TODO implement proper error catching for ProfileData init
            msg = (
                "There was an error when loading profile '{}'.\n".format(pfle)
                +
                "Would you like to delete it? Choosing 'No' will just ignore the profile."
            )
            sp_logging.G_LOGGER.info(msg)
            sp_logging.G_LOGGER.info(exep)
            res = show_message_dialog(msg, "Error", style="YES_NO")
            if res:
                # remove pfle
                print("removing:", os.path.join(sp_paths.PROFILES_PATH, pfle))
                os.remove(os.path.join(sp_paths.PROFILES_PATH, pfle))
                continue
            else:
                continue
    return profile_list
Exemplo n.º 7
0
 def onDeleteProfile(self, event):
     """Deletes the currently selected profile after getting confirmation."""
     profname = self.tc_name.GetLineText(0)
     fname = PROFILES_PATH + profname + ".profile"
     file_exists = os.path.isfile(fname)
     if not file_exists:
         msg = "Selected profile is not saved."
         show_message_dialog(msg, "Error")
         return
     # Open confirmation dialog
     dlg = wx.MessageDialog(
         None, "Do you want to delete profile:" + profname + "?",
         'Confirm Delete', wx.YES_NO | wx.ICON_QUESTION)
     result = dlg.ShowModal()
     if result == wx.ID_YES and file_exists:
         os.remove(fname)
     else:
         pass
Exemplo n.º 8
0
def list_profiles():
    """Lists profiles as initiated objects from the sp_paths.PROFILES_PATH."""
    files = sorted(os.listdir(sp_paths.PROFILES_PATH))
    profile_list = []
    for i in range(len(files)):
        try:
            profile_list.append(
                ProfileData(os.path.join(sp_paths.PROFILES_PATH, files[i])))
        except Exception as exep:  # TODO implement proper error catching for ProfileData init
            msg = "There was an error when loading profile '{}'. Exiting.".format(
                files[i])
            sp_logging.G_LOGGER.info(msg)
            sp_logging.G_LOGGER.info(exep)
            show_message_dialog(msg, "Error")
            exit()
        if sp_logging.DEBUG:
            sp_logging.G_LOGGER.info("Listed profile: %s",
                                     profile_list[i].name)
    return profile_list
Exemplo n.º 9
0
    def save(self):
        """Saves the TempProfile into a file."""
        if self.name is not None:
            fname = os.path.join(PROFILES_PATH, self.name + ".profile")
            try:
                tpfile = open(fname, "w")
            except IOError:
                msg = "Cannot write to file {}".format(fname)
                show_message_dialog(msg, "Error")
                return None
            tpfile.write("name=" + str(self.name) + "\n")
            if self.spanmode:
                tpfile.write("spanmode=" + str(self.spanmode) + "\n")
            if self.spangroups:
                tpfile.write("spangroups=" + str(self.spangroups) + "\n")
            if self.slideshow is not None:
                tpfile.write("slideshow=" + str(self.slideshow) + "\n")
            if self.delay:
                tpfile.write("delay=" + str(self.delay) + "\n")
            if self.sortmode:
                tpfile.write("sortmode=" + str(self.sortmode) + "\n")
            if self.inches:
                tpfile.write("diagonal_inches=" + str(self.inches) + "\n")
            if self.manual_offsets:
                tpfile.write("offsets=" + str(self.manual_offsets) + "\n")
            if self.bezels:
                tpfile.write("bezels=" + str(self.bezels) + "\n")
            if self.hk_binding:
                tpfile.write("hotkey=" + str(self.hk_binding) + "\n")
            if self.perspective:
                tpfile.write("perspective=" + str(self.perspective) + "\n")
            if self.paths_array:
                for paths in self.paths_array:
                    tpfile.write("display" +
                                 str(self.paths_array.index(paths)) +
                                 "paths=" + paths + "\n")

            tpfile.close()
            return fname
        else:
            print("tmp.Save(): name is not set.")
            return None
Exemplo n.º 10
0
    def onAlignTest(self, event):
        """Align test, takes alignment settings from open profile and sets a test image wp."""
        # Use the settings currently written out in the fields!
        testimage = [os.path.join(PATH, "superpaper/resources/test.png")]
        if not os.path.isfile(testimage[0]):
            print(testimage)
            msg = "Test image not found in {}.".format(testimage)
            show_message_dialog(msg, "Error")
        ppi = None
        inches = self.tc_inches.GetLineText(0).split(";")
        if (inches == "") or (len(inches) < NUM_DISPLAYS):
            msg = "You must enter a diagonal inch value for every \
display, serparated by a semicolon ';'."

            show_message_dialog(msg, "Error")

        # print(inches)
        inches = [float(i) for i in inches]
        bezels = self.tc_bez.GetLineText(0).split(";")
        bezels = [float(b) for b in bezels]
        offsets = self.tc_offsets.GetLineText(0).split(";")
        offsets = [[int(i.split(",")[0]),
                    int(i.split(",")[1])] for i in offsets]
        flat_offsets = []
        for off in offsets:
            for pix in off:
                flat_offsets.append(pix)
        # print("flat_offsets= ", flat_offsets)
        # Use the simplified CLI profile class
        get_display_data()
        profile = CLIProfileData(
            testimage,
            ppi,
            inches,
            bezels,
            flat_offsets,
        )
        change_wallpaper_job(profile)
Exemplo n.º 11
0
 def open_config(self, event):
     """Opens Superpaper config folder, CONFIG_PATH."""
     if platform.system() == "Windows":
         try:
             os.startfile(sp_paths.CONFIG_PATH)
         except BaseException:
             show_message_dialog(
                 "There was an error trying to open the config folder.")
     elif platform.system() == "Darwin":
         try:
             subprocess.check_call(["open", sp_paths.CONFIG_PATH])
         except subprocess.CalledProcessError:
             show_message_dialog(
                 "There was an error trying to open the config folder.")
     else:
         try:
             subprocess.check_call(['xdg-open', sp_paths.CONFIG_PATH])
         except subprocess.CalledProcessError:
             show_message_dialog(
                 "There was an error trying to open the config folder.")
Exemplo n.º 12
0
def set_wallpaper_linux(outputfile):
    """
    Wallpaper setter for Linux hosts.

    Functionality is based on the DESKTOP_SESSION environment variable,
    if it is not set, like often on window managers such as i3, the default
    behavior is to attempt to use feh as the communication layer with the
    desktop.

    On systems where the variable is set, a native way of setting the
    wallpaper can be used. These are DE specific.
    """
    file = "file://" + outputfile
    set_command = G_SET_COMMAND_STRING
    if sp_logging.DEBUG:
        sp_logging.G_LOGGER.info(file)

    desk_env = os.environ.get("DESKTOP_SESSION")
    if sp_logging.DEBUG:
        sp_logging.G_LOGGER.info("DESKTOP_SESSION is: '%s'", desk_env)

    if desk_env:
        if set_command != "":
            if set_command == "feh":
                subprocess.run(["feh", "--bg-scale", "--no-xinerama", outputfile])
            else:
                command_string_list = set_command.split()
                formatted_command = []
                for term in command_string_list:
                    formatted_command.append(term.format(image=outputfile))
                sp_logging.G_LOGGER.info("Formatted custom command is: '%s'", formatted_command)
                subprocess.run(formatted_command)
        elif desk_env in ["gnome", "gnome-wayland",
                          "unity", "ubuntu",
                          "pantheon", "budgie-desktop"]:
            subprocess.run(["gsettings", "set",
                            "org.gnome.desktop.background", "picture-uri",
                            file])
        elif desk_env in ["cinnamon"]:
            subprocess.run(["gsettings", "set",
                            "org.cinnamon.desktop.background", "picture-uri",
                            file])
        elif desk_env in ["mate"]:
            subprocess.run(["gsettings",
                            "set",
                            "org.mate.background",
                            "picture-filename",
                            outputfile])
        elif desk_env in ["xfce", "xubuntu"]:
            xfce_actions(outputfile)
        elif desk_env in ["lubuntu", "Lubuntu"]:
            try:
                subprocess.run("pcmanfm", "-w", outputfile)
            except OSError:
                try:
                    subprocess.run("pcmanfm-qt", "-w", outputfile)
                except OSError:
                    sp_logging.G_LOGGER.info("Exception: failure to find either command \
'pcmanfm' or 'pcmanfm-qt'. Exiting.")
                    sys.exit(1)
        elif desk_env in ["/usr/share/xsessions/plasma", "plasma"]:
            kdeplasma_actions(outputfile)
        elif "i3" in desk_env or desk_env in ["/usr/share/xsessions/bspwm"]:
            subprocess.run(["feh", "--bg-scale", "--no-xinerama", outputfile])
        else:
            if set_command == "":
                message = "Your DE could not be detected to set the wallpaper. \
You need to set the 'set_command' option in your \
settings file superpaper/general_settings. Exiting."
                sp_logging.G_LOGGER.info(message)
                show_message_dialog(message, "Error")
                sys.exit(1)
            else:
                os.system(set_command.format(image=outputfile))
    else:
        sp_logging.G_LOGGER.info("DESKTOP_SESSION variable is empty, \
attempting to use feh to set the wallpaper.")
        subprocess.run(["feh", "--bg-scale", "--no-xinerama", outputfile])
Exemplo n.º 13
0
    def register_hotkeys(self):
        """Registers system-wide hotkeys for profiles and application interaction."""
        if self.g_settings.use_hotkeys is True:
            try:
                # import keyboard # https://github.com/boppreh/keyboard
                # This import allows access to the specific errors in this method.
                from system_hotkey import (SystemHotkey, SystemHotkeyError,
                                           SystemRegisterError,
                                           UnregisterError, InvalidKeyError)
            except ImportError as import_e:
                sp_logging.G_LOGGER.info(
                    "WARNING: Could not import keyboard hotkey hook library, \
hotkeys will not work. Exception: %s", import_e)
            if "system_hotkey" in sys.modules:
                try:
                    # Keyboard bindings: https://github.com/boppreh/keyboard
                    #
                    # Alternative KB bindings for X11 systems and Windows:
                    # system_hotkey https://github.com/timeyyy/system_hotkey
                    # seen_binding = set()
                    # self.hk = SystemHotkey(check_queue_interval=0.05)
                    # self.hk2 = SystemHotkey(
                    #     consumer=self.profile_consumer,
                    #     check_queue_interval=0.05)

                    # Unregister previous hotkeys
                    if self.seen_binding:
                        for binding in self.seen_binding:
                            try:
                                self.hk.unregister(binding)
                                if sp_logging.DEBUG:
                                    sp_logging.G_LOGGER.info(
                                        "Unreg hotkey %s", binding)
                            except (SystemHotkeyError, UnregisterError,
                                    InvalidKeyError):
                                try:
                                    self.hk2.unregister(binding)
                                    if sp_logging.DEBUG:
                                        sp_logging.G_LOGGER.info(
                                            "Unreg hotkey %s", binding)
                                except (SystemHotkeyError, UnregisterError,
                                        InvalidKeyError):
                                    if sp_logging.DEBUG:
                                        sp_logging.G_LOGGER.info(
                                            "Could not unreg hotkey '%s'",
                                            binding)
                        self.seen_binding = set()

                    # register general bindings
                    if self.g_settings.hk_binding_next not in self.seen_binding:
                        try:
                            self.hk.register(self.g_settings.hk_binding_next,
                                             callback=lambda x: self.
                                             next_wallpaper(wx.EVT_MENU),
                                             overwrite=False)
                            self.seen_binding.add(
                                self.g_settings.hk_binding_next)
                        except (SystemHotkeyError, SystemRegisterError,
                                InvalidKeyError):
                            msg = "Error: could not register hotkey {}. \
Check that it is formatted properly and valid keys.".format(
                                self.g_settings.hk_binding_next)
                            sp_logging.G_LOGGER.info(msg)
                            sp_logging.G_LOGGER.info(sys.exc_info()[0])
                            show_message_dialog(msg, "Error")
                    if self.g_settings.hk_binding_pause not in self.seen_binding:
                        try:
                            self.hk.register(self.g_settings.hk_binding_pause,
                                             callback=lambda x: self.
                                             pause_timer(wx.EVT_MENU),
                                             overwrite=False)
                            self.seen_binding.add(
                                self.g_settings.hk_binding_pause)
                        except (SystemHotkeyError, SystemRegisterError,
                                InvalidKeyError):
                            msg = "Error: could not register hotkey {}. \
Check that it is formatted properly and valid keys.".format(
                                self.g_settings.hk_binding_pause)
                            sp_logging.G_LOGGER.info(msg)
                            sp_logging.G_LOGGER.info(sys.exc_info()[0])
                            show_message_dialog(msg, "Error")
                    # try:
                    # self.hk.register(('control', 'super', 'shift', 'q'),
                    #  callback=lambda x: self.on_exit(wx.EVT_MENU))
                    # except (SystemHotkeyError, SystemRegisterError, InvalidKeyError):
                    # pass

                    # register profile specific bindings
                    self.list_of_profiles = list_profiles()
                    for profile in self.list_of_profiles:
                        if sp_logging.DEBUG:
                            sp_logging.G_LOGGER.info(
                                "Registering binding: \
                                %s for profile: %s", profile.hk_binding,
                                profile.name)
                        if (profile.hk_binding is not None and
                                profile.hk_binding not in self.seen_binding):
                            try:
                                self.hk2.register(profile.hk_binding,
                                                  profile,
                                                  overwrite=False)
                                self.seen_binding.add(profile.hk_binding)
                            except (SystemHotkeyError, SystemRegisterError,
                                    InvalidKeyError):
                                msg = "Error: could not register hotkey {}. \
Check that it is formatted properly and valid keys.".format(profile.hk_binding)
                                sp_logging.G_LOGGER.info(msg)
                                sp_logging.G_LOGGER.info(sys.exc_info()[0])
                                show_message_dialog(msg, "Error")
                        elif profile.hk_binding in self.seen_binding:
                            msg = "Could not register hotkey: '{}' for profile: '{}'.\n\
It is already registered for another action.".format(profile.hk_binding,
                                                     profile.name)
                            sp_logging.G_LOGGER.info(msg)
                            show_message_dialog(msg, "Error")
                except (SystemHotkeyError, SystemRegisterError,
                        UnregisterError, InvalidKeyError):
                    if sp_logging.DEBUG:
                        sp_logging.G_LOGGER.info(
                            "Coulnd't register hotkeys, exception:")
                        sp_logging.G_LOGGER.info(sys.exc_info()[0])
Exemplo n.º 14
0
    def test_save(self):
        """Tests whether the user input for profile settings is valid."""
        valid_profile = False
        if self.name is not None and self.name.strip() is not "":
            fname = os.path.join(PROFILES_PATH, self.name + ".deleteme")
            try:
                testfile = open(fname, "w")
                testfile.close()
                os.remove(fname)
            except IOError:
                msg = "Cannot write to file {}".format(fname)
                show_message_dialog(msg, "Error")
                return False
            if self.spanmode == "single":
                if len(self.paths_array) > 1:
                    msg = "When spanning a single image across all monitors, \
only one paths field is needed."

                    show_message_dialog(msg, "Error")
                    return False
            if self.spanmode == "multi":
                if len(self.paths_array) < 2:
                    msg = "When setting a different image on every display, \
each display needs its own paths field."

                    show_message_dialog(msg, "Error")
                    return False
            if self.slideshow is True and not self.delay:
                msg = "When using slideshow you need to enter a delay."
                show_message_dialog(msg, "Info")
                return False
            if self.delay:
                try:
                    val = int(self.delay)
                    if val < 20:
                        msg = "It is advisable to set the slideshow delay to \
be at least 20 seconds due to the time the image processing takes."

                        show_message_dialog(msg, "Info")
                        return False
                except ValueError:
                    msg = "Slideshow delay must be an integer of seconds."
                    show_message_dialog(msg, "Error")
                    return False
            # if self.sortmode:
            # No test needed
            if self.inches:
                if self.is_list_float(self.inches):
                    pass
                else:
                    msg = "Display diagonals must be given in numeric values \
using decimal point and separated by semicolon ';'."

                    show_message_dialog(msg, "Error")
                    return False
            if self.manual_offsets:
                if self.is_list_offsets(self.manual_offsets):
                    pass
                else:
                    msg = "Display offsets must be given in width,height pixel \
pairs and separated by semicolon ';'."

                    show_message_dialog(msg, "Error")
                    return False
            if self.bezels:
                if self.is_list_float(self.bezels):
                    if self.manual_offsets:
                        if len(self.manual_offsets.split(";")) < len(
                                self.bezels.split(";")):
                            msg = "When using both offset and bezel \
corrections, take care to enter an offset for each display that you \
enter a bezel thickness."

                            show_message_dialog(msg, "Error")
                            return False
                        else:
                            pass
                    else:
                        pass
                else:
                    msg = "Display bezels must be given in millimeters using \
decimal point and separated by semicolon ';'."

                    show_message_dialog(msg, "Error")
                    return False
            if self.hk_binding:
                if self.is_valid_hotkey(self.hk_binding):
                    pass
                else:
                    msg = "Hotkey must be given as 'mod1+mod2+mod3+key'. \
Valid modifiers are 'control', 'super', 'alt', 'shift'."

                    show_message_dialog(msg, "Error")
                    return False
            if self.paths_array:
                if self.is_list_valid_paths(self.paths_array):
                    pass
                else:
                    # msg = "Paths must be separated by a semicolon ';'."
                    # show_message_dialog(msg, "Error")
                    return False
            else:
                msg = "You must enter at least one path for images."
                show_message_dialog(msg, "Error")
                return False
            # Passed all tests.
            valid_profile = True
            return valid_profile
        else:
            print("tmp.Save(): name is not set.")
            msg = "You must enter a name for the profile."
            show_message_dialog(msg, "Error")
            return False
Exemplo n.º 15
0
 def is_list_valid_paths(self, input_list):
     """Verifies that input list contains paths and that they're valid."""
     if input_list == [""]:
         msg = "At least one path for wallpapers must be given."
         show_message_dialog(msg, "Error")
         return False
     if "" in input_list:
         msg = "Add an image source for every display present."
         show_message_dialog(msg, "Error")
         return False
     if self.spangroups:
         num_groups = len(self.spangroups.split(','))
         if len(input_list) < num_groups:
             msg = "Add an image source for every span group."
             show_message_dialog(msg, "Error")
             return False
     for path_list_str in input_list:
         path_list = path_list_str.split(";")
         for path in path_list:
             if os.path.isdir(path) is True:
                 supported_files = [
                     f for f in os.listdir(path)
                     if f.endswith(wpproc.G_SUPPORTED_IMAGE_EXTENSIONS)
                 ]
                 if supported_files:
                     continue
                 else:
                     msg = "Path '{}' does not contain supported image files.".format(
                         path)
                     show_message_dialog(msg, "Error")
                     return False
             elif os.path.isfile(path) is True:
                 if path.endswith(wpproc.G_SUPPORTED_IMAGE_EXTENSIONS):
                     continue
                 else:
                     msg = "Image '{}' is not a supported image file.".format(
                         path)
                     show_message_dialog(msg, "Error")
                     return False
             else:
                 msg = "Path '{}' was not recognized as a directory.".format(
                     path)
                 show_message_dialog(msg, "Error")
                 return False
     valid_pathsarray = True
     return valid_pathsarray