From 0b7279c47df6b598e19a60cf60bca2d18d19eee0 Mon Sep 17 00:00:00 2001 From: John Elkins Date: Mon, 11 May 2009 21:46:48 -0500 Subject: [PATCH] Added swap_grid option, improved window filter, and removed xdotools dependency NEW - Added swap_grid option - Added program dependency checking - Added verbosity (-v) flags - Added widthadjustment stilerrc option - Added version and help information IMPROVED - Improved window filter performance and re-enabled it by default - Fixed center grid width calculation bugs - Re-factored code a little. - Fixed Positioning calculations to use OrigX and OrigY - Consolidated grid positioning and sizing calculations REMOVED - Removed dependency on xdotools --- README | 20 +- stiler.py | 564 +++++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 448 insertions(+), 136 deletions(-) diff --git a/README b/README index 77fb5a6..865e959 100644 --- a/README +++ b/README @@ -5,11 +5,10 @@ stiler.py is known to work with pekwm, openbox, metacity, and compiz. Requirements: wmctrl - used to get the window and desktop information and manage the windows -xdotools - used to get the currently active window -Usage: stiler.py OPTION +Usage: stiler.py layout_option [flags] -Standard options: +Standard layout_options: simple - The basic tiling layout . 1 Main + all other at the side. swap - Will swap the active window to master column cycle - Cycle all the windows in the master pane @@ -18,7 +17,7 @@ horizontal - Simple horizontal tiling maximize - Maximize the active window/ for openbox which doesn't permit resizing of max windows max_all - Maximize all windows -Grid options: +Grid layout_options: The following grid options mimic the functionality of compiz's grid plugin which in turn mimics the functionality of winsplit revolution. @@ -33,7 +32,13 @@ bottom_right - Place the active window in the bottom right corner of the scre Multiple calls to any of the grid options on the same active window will select different widths. -On first run stiler will create a config file ~/.stilerrc. Modify the values to suit your window decorations/Desktop padding. +On first run stiler will create a config file ~/.stilerrc. Modify the values to suit your window decorations/Desktop padding. The two most influential values are the winborder and wintitle values. + +Flags: + +-v - Enable INFO level verbosity +-vv - Enable DEBUG level verbosity +-h - Display usage information ~/.stilerrc file options: @@ -50,16 +55,17 @@ wintitle - pads the given number of pixels above each window miscellaneous options tempfile - cache file for holding window positions +windowfilter - exclude minimized and UTILITY windows from being tiled simple layout options: mwfactor - width of the bigger window in the simple layout -windowfilter - exclude minimized and UTILITY windows from being tiled grid layout options: monitors - for a dual monitor setup set this to 2 -gridwidths - a list of grid widths to use for splitting the screen. 0.33 should always be in the list +gridwidths - a list of locations on the screen at which to place the borders of the grid. Each location is mirrored across 1/2 the screen. For example, a gridwidths list of 0.17,0.33,0.50 creates grid borders at 0.17,0.33,0.50,0.67,0.83 +widthadjustment - sometimes the gridwidths end up being rounded too high or low which can be common in a dual monitor setup. Use the widthadjustment to account for rounding error. If you need other layouts modify get_simple_tile diff --git a/stiler.py b/stiler.py index 403ee6c..3ea03f4 100755 --- a/stiler.py +++ b/stiler.py @@ -1,7 +1,9 @@ -#!/usr/bin/python +#!/usr/bin/env python ############################################################################ -# Copyright (c) 2009 unohu # +# Copyright (c) 2009 unohu and Contributors # +# # +# Contributors: John Elkins # # # # Permission to use, copy, modify, and/or distribute this software for any # # purpose with or without fee is hereby granted, provided that the above # @@ -23,10 +25,19 @@ import commands import pickle import ConfigParser +import inspect +import logging + +PROGRAM_NAME = "Simple Window Tiler" +PROGRAM_VERSION = "0.2" +PROGRAM_SOURCE = "http://github.com/soulfx/stiler/tree/grid" -usage = sys.argv[0] + " option" +logging.basicConfig(level=logging.WARN) +log = logging.getLogger() +log.name = PROGRAM_NAME def initconfig(): + rcfile=os.getenv('HOME')+"/.stilerrc" configDefaults={ @@ -38,15 +49,17 @@ def initconfig(): 'WinBorder': '1', 'MwFactor': '0.65', 'Monitors': '1', - 'GridWidths': '0.50,0.67,0.33', + 'GridWidths': '0.33,0.50', + 'WidthAdjustment':'0.0', 'TempFile': '/tmp/tile_winlist', - 'WindowFilter':'off', + 'WindowFilter':'on', } config=ConfigParser.RawConfigParser(configDefaults) if not os.path.exists(rcfile): + log.info("writing new config file to "+rcfile) cfg=open(rcfile,'w') config.write(cfg) cfg.close() @@ -54,8 +67,56 @@ def initconfig(): config.read(rcfile) return config +def version_option(): + """ + Display program version information + """ + print "%s %s <%s>" % (PROGRAM_NAME,PROGRAM_VERSION,PROGRAM_SOURCE) + +def v_flag(): + """ + Enable INFO level verbosity + """ + log.setLevel(logging.INFO) + +def vv_flag(): + """ + Enable DEBUG level verbosity + """ + log.setLevel(logging.DEBUG) + +def has_required_programs(program_list): + """ + Returns true if all the programs in the program_list are on the system + """ + + returnValue = True + + for program in program_list: + if commands.getstatusoutput("which "+program)[0] != 0: + log.error(program+" is required by "+PROGRAM_NAME) + returnValue = False + + return returnValue + +def is_valid_window(window): + """ + Returns True if the given window should be tiled, False otherwise + """ + + if WindowFilter == True: + window_type = commands.getoutput("xprop -id "+window+" _NET_WM_WINDOW_TYPE | cut -d_ -f10").split("\n")[0] + window_state = commands.getoutput("xprop -id "+window+" WM_STATE | grep \"window state\" | cut -d: -f2").split("\n")[0].lstrip() + + logging.debug("%s is type %s, state %s" % (window,window_type,window_state)) + + if window_type == "UTILITY" or window_type == "DESKTOP" or window_state == "Iconic" : + return False + + return True def initialize(): + desk_output = commands.getoutput("wmctrl -d").split("\n") desk_list = [line.split()[0] for line in desk_output] @@ -77,16 +138,23 @@ def initialize(): def get_active_window(): - active_window_list = str(hex(int(commands.getoutput("xdotool getactivewindow 2>/dev/null").split()[0]))) - return filter_excluded(active_window_list) - -# return a list of [width,height] -def get_active_window_width_height(): - active_window = get_active_window() - return commands.getoutput(" xwininfo -id "+active_window+" | egrep \"Height|Width\" | cut -d: -f2 | tr -d \" \"").split("\n") + active = commands.getoutput("xprop -root _NET_ACTIVE_WINDOW | cut -d' ' -f5 | cut -d',' -f1") + if is_valid_window(active) == True: + logging.debug("obtained active window: '"+str(active)+"'") + return active + else: + return 0 + +def get_window_width_height(window_id): + """ + return the given window's [width, height] + """ + return commands.getoutput(" xwininfo -id "+window_id+" | egrep \"Height|Width\" | cut -d: -f2 | tr -d \" \"").split("\n") -# return a list of [x,y] def get_window_x_y(windowid): + """ + return the given window's [x,y] position + """ return commands.getoutput("xwininfo -id "+windowid+" | grep 'Corners' | cut -d' ' -f5 | cut -d'+' -f2,3").split("+") def store(object,file): @@ -107,47 +175,23 @@ def retrieve(file): dict = {} return (dict) - -# Get all global variables -Config = initconfig() -cfgSection="DEFAULT" -if Config.has_section("default"): - cfgSection="default" - -BottomPadding = Config.getint(cfgSection,"BottomPadding") -TopPadding = Config.getint(cfgSection,"TopPadding") -LeftPadding = Config.getint(cfgSection,"LeftPadding") -RightPadding = Config.getint(cfgSection,"RightPadding") -WinTitle = Config.getint(cfgSection,"WinTitle") -WinBorder = Config.getint(cfgSection,"WinBorder") -MwFactor = Config.getfloat(cfgSection,"MwFactor") -TempFile = Config.get(cfgSection,"TempFile") -Monitors = Config.getint(cfgSection,"Monitors") -WindowFilter = Config.getboolean(cfgSection,"WindowFilter") -CORNER_WIDTHS = map(lambda y:float(y)/Monitors,Config.get(cfgSection,"GridWidths").split(",")) -CENTER_WIDTHS = [1.0/Monitors,min(CORNER_WIDTHS)] - -(Desktop,OrigXstr,OrigYstr,MaxWidthStr,MaxHeightStr,WinList) = initialize() -MaxWidth = int(MaxWidthStr) - LeftPadding - RightPadding -MaxHeight = int(MaxHeightStr) - TopPadding - BottomPadding -OrigX = int(OrigXstr) + LeftPadding -OrigY = int(OrigYstr) + TopPadding -OldWinList = retrieve(TempFile) - -# give the current closest width def get_width_constant(width, width_constant_array): + """ + Returns the current closest width constant from the given constant_array and given current width + """ return min ( map (lambda y: [abs(y-width),y], width_constant_array))[1] -# get the next width in the width_constant_array def get_next_width(current_width,width_array): - + """ + Returns the next width to use based on the given current width, and width constants + """ active_width = float(current_width)/MaxWidth active_width_constant = width_array.index(get_width_constant(active_width,width_array)) width_multiplier = width_array[(active_width_constant+1)%len(width_array)] - return int(MaxWidth*width_multiplier) + return int((MaxWidth-(WinBorder*2))*width_multiplier) def get_simple_tile(wincount): rows = wincount - 1 @@ -210,8 +254,15 @@ def move_active(PosX,PosY,Width,Height): move_window(windowid,PosX,PosY,Width,Height) -# resize and move the given window def move_window(windowid,PosX,PosY,Width,Height): + """ + Resizes and moves the given window to the given position and dimensions + """ + PosX = int(PosX) + PosY = int(PosY) + + logging.debug("moving window: %s to (%s,%s,%s,%s) " % (windowid,PosX,PosY,Width,Height)) + if windowid == ":ACTIVE:": window = "-r "+windowid else: @@ -221,10 +272,10 @@ def move_window(windowid,PosX,PosY,Width,Height): # unmaximize os.system("wmctrl "+window+" -b remove,maximized_vert,maximized_horz") # resize - command = " wmctrl " + window + " -e 0,-1,-1," + str(Width) + "," + str(Height) + command = "wmctrl " + window + " -e 0,-1,-1," + str(Width) + "," + str(Height) os.system(command) # move - command = " wmctrl " + window + " -e 0," + str(PosX) + "," + str(PosY)+ ",-1,-1" + command = "wmctrl " + window + " -e 0," + str(max(PosX,0)) + "," + str(max(PosY,0))+ ",-1,-1" os.system(command) # set properties command = "wmctrl " + window + " -b remove,hidden,shaded" @@ -239,101 +290,161 @@ def raise_window(windowid): os.system(command) -def bottom(): - active = get_active_window() - Width=get_next_width(int(get_active_window_width_height()[0]),CENTER_WIDTHS) - Height=(MaxHeight - WinBorder)/2 - WinTitle - PosX = get_next_posx(int(get_window_x_y(active)[0]),Width+WinBorder/2); - PosY=MaxHeight/2+WinTitle - move_window(active,PosX,PosY,Width,Height) - raise_window(active) - def get_next_posx(current_x,new_width): PosX = 0 if current_x < MaxWidth/Monitors: if new_width < MaxWidth/Monitors - WinBorder: - PosX=LeftPadding+new_width + PosX=OrigX+new_width else: - PosX=LeftPadding + PosX=OrigX else: if new_width < MaxWidth/Monitors - WinBorder: - PosX=MaxWidth/Monitors+LeftPadding+new_width + PosX=MaxWidth/Monitors+OrigX+new_width else: - PosX=LeftPadding+MaxWidth/Monitors + PosX=OrigX+MaxWidth/Monitors return PosX -def top(): +def top_option(): + """ + Place the active window along the top of the screen + """ active = get_active_window() - Width=get_next_width(int(get_active_window_width_height()[0]),CENTER_WIDTHS) - Height=(MaxHeight -WinBorder)/2 - WinTitle - PosX = get_next_posx(int(get_window_x_y(active)[0]),Width+WinBorder/2); - PosY=TopPadding + Width=get_middle_Width(active) + Height=get_top_Height() + PosX = get_middle_PosX(active,Width) + PosY=get_top_PosY() move_window(active,PosX,PosY,Width,Height) raise_window(active) -def middle(): +def middle_option(): + """ + Place the active window in the middle of the screen + """ active = get_active_window() - Width=get_next_width(int(get_active_window_width_height()[0]),CENTER_WIDTHS) - Height=MaxHeight - WinTitle -WinBorder - PosX = get_next_posx(int(get_window_x_y(active)[0]),Width+WinBorder/2); - PosY=TopPadding + Width=get_middle_Width(active) + Height=get_middle_Height() + PosX = get_middle_PosX(active,Width) + PosY= get_middle_PosY() move_window(active,PosX,PosY,Width,Height) raise_window(active) -def top_left(): +def top_left_option(): + """ + Place the active window in the top left corner of the screen + """ active = get_active_window() - Width=get_next_width(int(get_active_window_width_height()[0]),CORNER_WIDTHS) - WinBorder - Height=(MaxHeight -WinBorder)/2 - WinTitle - PosX = get_next_posx(int(get_window_x_y(active)[0]),0); - PosY=TopPadding + Width=get_corner_Width(active) + Height=get_top_Height() + PosX = get_left_PosX(active,Width) + PosY=get_top_PosY() move_window(active,PosX,PosY,Width,Height) raise_window(active) -def top_right(): +def top_right_option(): + """ + Place the active window in the top right corner of the screen + """ active = get_active_window() - Width=get_next_width(int(get_active_window_width_height()[0]),CORNER_WIDTHS) - WinBorder - Height=(MaxHeight -WinBorder)/2 - WinTitle - PosX = get_next_posx(int(get_window_x_y(active)[0]),MaxWidth/Monitors-Width); - PosY=TopPadding + Width=get_corner_Width(active) + Height=get_top_Height() + PosX = get_right_PosX(active,Width) + PosY=get_top_PosY() + move_window(active,PosX,PosY,Width,Height) + raise_window(active) + +def get_top_Height(): + return get_bottom_Height() + +def get_middle_Height(): + return MaxHeight - WinTitle - WinBorder + +def get_bottom_Height(): + return MaxHeight/2 - WinTitle - WinBorder + +def get_bottom_PosY(): + return MaxHeight/2 + OrigY + WinBorder/2 - (BottomPadding)/WinBorder + +def get_middle_PosY(): + return get_top_PosY() + +def get_top_PosY(): + return OrigY - TopPadding/WinBorder + +def get_middle_Width(active): + return get_next_width(int(get_window_width_height(active)[0]),CENTER_WIDTHS)+WinBorder + +def get_corner_Width(active): + return get_next_width(int(get_window_width_height(active)[0]),CORNER_WIDTHS) + +def get_middle_PosX(active, Width): + return get_next_posx(int(get_window_x_y(active)[0]),(MaxWidth/Monitors-Width)/2) + WinBorder/4 + +def get_right_PosX(active,Width): + return get_next_posx(int(get_window_x_y(active)[0]),MaxWidth/Monitors-Width) - (RightPadding+LeftPadding)/WinBorder + +def get_left_PosX(active,Width): + return get_next_posx(int(get_window_x_y(active)[0]),0) + +def bottom_option(): + """ + Place the active window along the bottom of the screen + """ + active = get_active_window() + Width= get_middle_Width(active) + Height=get_bottom_Height() + PosX = get_middle_PosX(active,Width) + PosY=get_bottom_PosY() move_window(active,PosX,PosY,Width,Height) raise_window(active) -def bottom_right(): +def bottom_right_option(): + """ + Place the active window in the bottom right corner of the screen + """ active = get_active_window() - Width=get_next_width(int(get_active_window_width_height()[0]),CORNER_WIDTHS) - WinBorder - Height=(MaxHeight -WinBorder)/2 - WinTitle - PosX = get_next_posx(int(get_window_x_y(active)[0]),MaxWidth/Monitors-Width); - PosY=MaxHeight/2 + WinTitle + Width=get_corner_Width(active) + Height=get_bottom_Height() + PosX = get_right_PosX(active,Width) + PosY=get_bottom_PosY() move_window(active,PosX,PosY,Width,Height) raise_window(active) -def bottom_left(): +def bottom_left_option(): + """ + Place the active window in the bottom left corner of the screen + """ active = get_active_window() - Width=get_next_width(int(get_active_window_width_height()[0]),CORNER_WIDTHS) - WinBorder - Height=(MaxHeight -WinBorder)/2 - WinTitle - PosX = get_next_posx(int(get_window_x_y(active)[0]),0); - PosY=MaxHeight/2 + WinTitle + Width=get_corner_Width(active) + Height=get_bottom_Height() + PosX = get_left_PosX(active,Width) + PosY=get_bottom_PosY() move_window(active,PosX,PosY,Width,Height) raise_window(active) -def left(): +def left_option(): + """ + Place the active window in the left corner of the screen + """ active = get_active_window() - Width=get_next_width(int(get_active_window_width_height()[0]),CORNER_WIDTHS) - WinBorder - Height=MaxHeight - WinTitle -WinBorder - PosX = get_next_posx(int(get_window_x_y(active)[0]),0); - PosY=TopPadding + Width=get_corner_Width(active) + Height=get_middle_Height() + PosX = get_left_PosX(active,Width) + PosY=get_middle_PosY() move_window(active,PosX,PosY,Width,Height) raise_window(active) -def right(): +def right_option(): + """ + Place the active window in the right corner of the screen + """ active = get_active_window() - Width=get_next_width(int(get_active_window_width_height()[0]),CORNER_WIDTHS) - WinBorder - Height=MaxHeight - WinTitle - WinBorder - PosX = get_next_posx(int(get_window_x_y(active)[0]),MaxWidth/Monitors-Width); - PosY=TopPadding + Width=get_corner_Width(active) + Height=get_middle_Height() + PosX = get_right_PosX(active,Width) + PosY=get_middle_PosY() move_window(active,PosX,PosY,Width,Height) raise_window(active) @@ -361,22 +472,9 @@ def create_win_list(): else: Windows = compare_win_list(Windows,OldWindows) - Windows = filter_excluded(Windows) - - return Windows - - -# remove windows that shouldn't be tiled -def filter_excluded(Windows): - - if WindowFilter == True and (sys.argv[1] == "swap" or sys.argv[1] == "cycle" or sys.argv[1] == "simple") : - - for win in Windows: - window_type = commands.getoutput("xprop -id "+win+" _NET_WM_WINDOW_TYPE | cut -d_ -f10").split("\n")[0] - window_state = commands.getoutput("xprop -id "+win+" WM_STATE | grep \"window state\" | cut -d: -f2").split("\n")[0] - - if window_type == "UTILITY" or window_state == " Iconic" : - Windows.remove(win) + for win in Windows: + if is_valid_window(win) == False: + Windows.remove(win) return Windows @@ -387,12 +485,56 @@ def arrange(layout,windows): store(WinList,TempFile) -def simple(): +def simple_option(): + """ + The basic tiling layout . 1 Main + all other at the side. + """ Windows = create_win_list() arrange(get_simple_tile(len(Windows)),Windows) + +def swap_windows(window1,window2): + """ + Swap window1 and window2 + """ + window1_area = map(lambda y:int(y),get_window_width_height(window1)) + window1_position = map(lambda y:int(y)-WinBorder/2,get_window_x_y(window1)) + window2_area = map(lambda y:int(y),get_window_width_height(window2)) + window2_position = map(lambda y:int(y)-WinBorder/2,get_window_x_y(window2)) + + move_window(window1,window2_position[0],window2_position[1]-WinTitle,window2_area[0],window2_area[1]) + move_window(window2,window1_position[0],window1_position[1]-WinTitle,window1_area[0],window1_area[1]) + +def get_largest_window(): + """ + Returns the window id of the window with the largest area + """ + winlist = create_win_list() + + max_area = 0; + max_win = winlist[0] + + for win in winlist: + win_area = reduce(lambda x,y:int(x)*int(y),get_window_width_height(win)) + if win_area > max_area: + max_area = win_area + max_win = win + + return max_win +def swap_grid_option(): + """ + Swap the active window with the largest window + """ + active_window = get_active_window() + largest_window = get_largest_window() + + swap_windows(active_window,largest_window) + raise_window(active_window) -def swap(): +def swap_option(): + """ + Will swap the active window to master column + """ winlist = create_win_list() active = get_active_window() winlist.remove(active) @@ -400,7 +542,10 @@ def swap(): arrange(get_simple_tile(len(winlist)),winlist) -def vertical(): +def vertical_option(): + """ + Simple vertical tiling + """ winlist = create_win_list() active = get_active_window() winlist.remove(active) @@ -408,22 +553,29 @@ def vertical(): arrange(get_vertical_tile(len(winlist)),winlist) -def horizontal(): +def horizontal_option(): + """ + Simple horizontal tiling + """ winlist = create_win_list() active = get_active_window() winlist.remove(active) winlist.insert(0,active) arrange(get_horiz_tile(len(winlist)),winlist) - -def cycle(): +def cycle_option(): + """ + Cycle all the windows in the master pane + """ winlist = create_win_list() winlist.insert(0,winlist[len(winlist)-1]) winlist = winlist[:-1] arrange(get_simple_tile(len(winlist)),winlist) - -def maximize(): +def maximize_option(): + """ + Maximize the active window + """ Width=MaxWidth Height=MaxHeight - WinTitle -WinBorder PosX=LeftPadding @@ -431,16 +583,170 @@ def maximize(): move_active(PosX,PosY,Width,Height) raise_window(":ACTIVE:") -def max_all(): +def max_all_option(): + """ + Maximize all windows + """ winlist = create_win_list() active = get_active_window() winlist.remove(active) winlist.insert(0,active) arrange(get_max_all(len(winlist)),winlist) -if len(sys.argv) == 1: - print usage - sys.exit(1) +def h_flag(): + """ + Display usage information + """ + help_option() + +def help_option(): + """ + Display usage information + """ + print "\nUsage: %s [FLAG] [OPTION]\n" % os.path.basename(sys.argv[0]) + + option_list = [] + flag_list = [] + + for key,value in globals().items(): + if inspect.isfunction(value): + if key.endswith("_option"): + option_list.append((key.rsplit("_",1)[0],inspect.getdoc(value))) + elif key.endswith("_flag"): + flag_list.append((key.rsplit("_",1)[0],inspect.getdoc(value))) + + option_list.sort() + flag_list.sort() + + print " Options:" + for option,description in option_list: + print " %-16s - %s" % (option,description) + + print "" + + print " Flags:" + for flag,description in flag_list: + print " -%-16s - %s" % (flag,description) + + print "" + version_option() + +def eval_function(function_string): + """ + Evaulate the given function. + """ + for key,value in globals().items(): + if key == function_string and inspect.isfunction(value): + value() + return + + log.warn("Unrecognized option: "+function_string.rsplit("_",1)[0]) + +def initialize_global_variables(): + """ + Initialize the global variables + """ + + # Screen Padding + global BottomPadding, TopPadding, LeftPadding, RightPadding + # Window Decoration + global WinTitle, WinBorder + # Grid Layout + global CORNER_WIDTHS, CENTER_WIDTHS, Monitors, WidthAdjustment + # Simple Layout + global MwFactor + # System Desktop and Screen Information + global MaxWidth, MaxHeight, OrigX, OrigY, Desktop, WinList, OldWinList + # Miscellaneous + global TempFile, WindowFilter + + Config = initconfig() + cfgSection="DEFAULT" + + # use "default" for configurations written using the original stiler + if Config.has_section("default"): + cfgSection="default" + + BottomPadding = Config.getint(cfgSection,"BottomPadding") + TopPadding = Config.getint(cfgSection,"TopPadding") + LeftPadding = Config.getint(cfgSection,"LeftPadding") + RightPadding = Config.getint(cfgSection,"RightPadding") + WinTitle = Config.getint(cfgSection,"WinTitle") + WinBorder = Config.getint(cfgSection,"WinBorder") + MwFactor = Config.getfloat(cfgSection,"MwFactor") + TempFile = Config.get(cfgSection,"TempFile") + Monitors = Config.getint(cfgSection,"Monitors") + WidthAdjustment = Config.getfloat(cfgSection,"WidthAdjustment") + WindowFilter = Config.getboolean(cfgSection,"WindowFilter") + CORNER_WIDTHS = map(lambda y:float(y),Config.get(cfgSection,"GridWidths").split(",")) + + # create the opposite section for each corner_width + opposite_widths = [] + for width in CORNER_WIDTHS: + opposite_widths.append(round(abs(1.0-width),2)) + + # add the opposites + CORNER_WIDTHS.extend(opposite_widths) + + CORNER_WIDTHS=list(set(CORNER_WIDTHS)) # filter out any duplicates + CORNER_WIDTHS.sort() + + CENTER_WIDTHS = filter(lambda y: y < 0.5, CORNER_WIDTHS) + CENTER_WIDTHS = map(lambda y:round(abs(y*2-1.0),2),CENTER_WIDTHS) + CENTER_WIDTHS.append(1.0) # always allow max for centers + CENTER_WIDTHS = list(set(CENTER_WIDTHS)) # filter dups + CENTER_WIDTHS.sort() + + # Handle multiple monitors + CORNER_WIDTHS=map(lambda y:round(y/Monitors,2)+WidthAdjustment,CORNER_WIDTHS) + CENTER_WIDTHS=map(lambda y:round(y/Monitors,2)+WidthAdjustment,CENTER_WIDTHS) + + logging.debug("corner widths: %s" % CORNER_WIDTHS) + logging.debug("center widths: %s" % CENTER_WIDTHS) + + (Desktop,OrigXstr,OrigYstr,MaxWidthStr,MaxHeightStr,WinList) = initialize() + MaxWidth = int(MaxWidthStr) - LeftPadding - RightPadding + MaxHeight = int(MaxHeightStr) - TopPadding - BottomPadding + OrigX = int(OrigXstr) + LeftPadding + OrigY = int(OrigYstr) + TopPadding + OldWinList = retrieve(TempFile) + + +def main(): + """ + Determine what needs to be done. + """ + + # we need options! + if len(sys.argv) == 1: + help_option() + sys.exit(1) + + # check and set any flags passed from the command line + for arg in sys.argv: + if arg == sys.argv[0]: + continue + elif arg.startswith("-"): + eval_function(arg.split("-")[1]+"_flag") + + # check to see if the system has all the required programs + required_programs=["wmctrl","xprop","xwininfo"] + if has_required_programs(required_programs) == False: + sys.exit(1) + + initialize_global_variables() + + # parse the args to determine what should be done + for arg in sys.argv: + if arg == sys.argv[0]: + continue + elif arg.startswith("-"): + continue + else: + eval_function(arg+"_option") + +if __name__ == "__main__": + main() else: - eval(sys.argv[1]+"()") + log.warn("Importing is not fully tested. Use at your own risk.")