SEARCH

Enter your search query in the box above ^, or use the forum search tool.

You are not logged in.

#276 2012-07-01 19:29:46

mrpeachy
20% cooler
From: The Everfree Forest
Registered: 2009-11-08
Posts: 3,460

Re: interactive conky

heres an idea i had, turned out to be quite easy to do
movable conky
http://www.youtube.com/watch?v=rfVqxYhv … e=youtu.be

this is what does it

--[[click tutorial lua by mrpeachy - thanks to barrybarrykelly for the xdotool method and gmonti for finding the deb files for the xdotool
in conkyrc, in addition to regular settings:

own_window_title clicky
lua_load ~/lua/clicky.lua
lua_draw_hook_pre main
TEXT
]]

require 'cairo'

click_start=1-- this starts the clickfunction
buttons={}--this table ini9tially holds the values from the buttons
p_start=1
position={}
--setup start positions

function conky_main()
if conky_window == nil then return end
local cs = cairo_xlib_surface_create(conky_window.display, conky_window.drawable, conky_window.visual, conky_window.width, conky_window.height)
cr = cairo_create(cs)
local updates=tonumber(conky_parse('${updates}'))
--get click data
local localx,localy,localnowx,localnowy=clickfunction()
--[[
options 
button_name="test_button",--name must be unique
blx=300.5,--bottom left x of button
bly=200.5,--bottom left y of button
height=60,--height
width=60,--width
draw=1,--want button drawn? 1==yes, 0==no
fill_off=0,--fill type when off, 1=filled in, 0=outline
color_off={1,1,1,1},--color of button when off- red, green, blue, alpha
line_width_off=1,--if outline, then set line width
turn_off={}, --list other buttons that this button should turn off
fill_on=0,--fill type when on
color_on={1,0,0,1},--color of button when on
line_width_on=1,--if outline, then set line width
turn_on={}, --list other buttons that this button should turn on
localx=localx,--send function click data
localy=localy,--send function click data
]]
if p_start==1 then
position[1]=200
position[2]=200
p_start=0
end

--on off button 1
local test=onoff({
button_name="B1",
blx=position[1],bly=position[2],height=60,width=60,
draw=1,
--when button is off
fill_off=0,color_off={1,1,1,1},line_width_off=2,
turn_off={"B2",},
--when button is on
fill_on=1,color_on={1,0,0,1},line_width_on=0,
turn_on={},
--click data
localx=localx,localy=localy,})
--end of on off button 1
if test==1 then
position[1]=localnowx
position[2]=localnowy
cairo_select_font_face (cr, "mono", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size (cr, 10)
cairo_set_source_rgba (cr,1,1,1,1)
cairo_move_to (cr,localnowx+12,localnowy+12)
cairo_show_text (cr,localnowx.." / "..localnowy)
end

cairo_select_font_face (cr, "mono", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size (cr, 14)
cairo_set_source_rgba (cr,1,1,1,1)
cairo_move_to (cr,position[1]+2,position[2]-40)
cairo_show_text (cr,"CPU:"..conky_parse("${cpu cpu0}"))
cairo_move_to (cr,position[1]+2,position[2]-20)
cairo_show_text (cr,"MEM:"..conky_parse("${memperc}"))

--mouse over button 1
local test=mouse_over({
button_name="B1mo",
blx=position[1],bly=position[2],height=60,width=60,
draw=0,
--when button is off
fill_off=0,color_off={1,1,1,1},line_width_off=1,
turn_off={},
--when button is on
fill_on=1,color_on={1,0,0,1},line_width_on=0,
turn_on={},
--click data
localx=localnowx,localy=localnowy,})
--end of mouse over button 1





--#########################################################################################################
cairo_destroy(cr)
cairo_surface_destroy(cs)
cr=nil
end-- end main function

function onoff(button_data)
local button_name=button_data.button_name
if button_name==nil then print ("button needs a name") end
local blx=button_data.blx or 20
local bly=button_data.bly or 20
local height=button_data.height or 20
local width=button_data.width or 20
local localx=button_data.localx
local localy=button_data.localy
local turn_off=button_data.turn_off
local turn_on=button_data.turn_on
if localx>=blx and localx<=blx+width and localy<=bly and localy>=bly-height and buttons[tostring(button_name)]~=1 then
buttons[tostring(button_name)]=1
--turn on other buttons as set
    for i=1,#turn_on do
    buttons[tostring(turn_on[i])]=1
    end
elseif localx>=blx and localx<=blx+width and localy<=bly and localy>=bly-height and buttons[tostring(button_name)]==1 then
buttons[tostring(button_name)]=0
--turn off other buttons as set
    for i=1,#turn_off do
    buttons[tostring(turn_off[i])]=0
    end
elseif localx<blx and localx>blx+width and localy<bly and localy>bly-height and buttons[tostring(button_name)]~=1 then
buttons[tostring(button_name)]=0
--turn off other buttons as set
    for i=1,#turn_off do
    buttons[tostring(turn_off[i])]=0
    end
end
--draw bpx if requested
local draw=button_data.draw or 0
if draw==1 and buttons[tostring(button_name)]==0 or buttons[tostring(button_name)]==nil then
local color=button_data.color_off or {1,1,1,1}
local fill=button_data.fill_off or 0
local line_width=button_data.line_width_off or 1
buttondraw(blx,bly,height,width,color,fill,line_width)
elseif draw==1 and buttons[tostring(button_name)]==1 then
local color=button_data.color_on or {1,0,0,1}
local fill=button_data.fill_on or 0
local line_width=button_data.line_width_on or 1
buttondraw(blx,bly,height,width,color,fill,line_width)
end
--return if button is on,1 or off 0
return buttons[tostring(button_name)]
end

function mouse_over(button_data)
local button_name=button_data.button_name
if button_name==nil then print ("button needs a name") end
local blx=button_data.blx or 20
local bly=button_data.bly or 20
local height=button_data.height or 20
local width=button_data.width or 20
local localx=button_data.localx
local localy=button_data.localy
local turn_off=button_data.turn_off
local turn_on=button_data.turn_on
if localx>=blx and localx<=blx+width and localy<=bly and localy>=bly-height then
buttons[tostring(button_name)]=1
--turn on other buttons as set
    for i=1,#turn_on do
    buttons[tostring(turn_on[i])]=1
    end
elseif localx<blx or localx>blx+width or localy>bly or localy<bly-height then
buttons[tostring(button_name)]=0
--turn off other buttons as set
    for i=1,#turn_off do
    buttons[tostring(turn_off[i])]=0
    end
end
--draw bpx if requested
local draw=button_data.draw or 0
if draw==1 and buttons[tostring(button_name)]==0 or buttons[tostring(button_name)]==nil then
local color=button_data.color_off or {1,1,1,1}
local fill=button_data.fill_off or 0
local line_width=button_data.line_width_off or 1
buttondraw(blx,bly,height,width,color,fill,line_width)
elseif draw==1 and buttons[tostring(button_name)]==1 then
local color=button_data.color_on or {1,0,0,1}
local fill=button_data.fill_on or 0
local line_width=button_data.line_width_on or 1
buttondraw(blx,bly,height,width,color,fill,line_width)
end
--return if button is on,1 or off 0
return buttons[tostring(button_name)]
end







--button drawing function
function buttondraw(blx,bly,height,width,color,fill,line_width)
cairo_set_line_width (cr,line_width)
cairo_set_source_rgba (cr,color[1],color[2],color[3],color[4])
cairo_rectangle (cr,blx,bly,width,-height)
if fill==0 then
cairo_stroke (cr)
elseif fill==1 then
cairo_fill (cr)
end
end--of buttondraw function

--clickfunction, this runs xdotool and xwininfo and reads the coordinates of clicks
function clickfunction()
--start click logging and calculations ##########################################
if click_start==1 then
xdot=conky_parse("${if_running xdotool}1${else}0${endif}")
if tonumber(xdot)==1 then
os.execute("killall xdotool && echo 'xdo killed' &")
end
os.execute("xdotool search --name 'conky' behave %@ mouse-click getmouselocation >> /tmp/xdo &")
local f = io.popen("xwininfo -name 'conky' | grep 'Absolute'")
geometry = f:read("*a")
f:close()
local geometry=string.gsub(geometry,"[\n]","")
print (geometry)
s,f,abstlx=string.find(geometry,"X%p%s*(%p*%d*)")
s,f,abstly=string.find(geometry,"Y%p%s*(%p*%d*)")
click_start=nil
end--if click_start=1 ######################################
--click calculations #################################
local f=io.open("/tmp/xdo")
click=f:read()
f:close()
if click~=nil then
local f = io.open("/tmp/xdo","w")
f:write("")
f:close() 
end--if click=nil
if click==nil then click="x:0 y:0 " end
--print (click)
local s,f,mousex=string.find(click,"x%p(%d*)%s")
local s,f,mousey=string.find(click,"y%p(%d*)%s")
localx=tonumber(mousex)-abstlx
localy=tonumber(mousey)-abstly
--get now location
os.execute("xdotool getmouselocation > /tmp/xdonow ")
local f=io.open("/tmp/xdonow")
mousenow=f:read()
f:close()
local s,f,mousenowx=string.find(mousenow,"x%p(%d*)%s")
local s,f,mousenowy=string.find(mousenow,"y%p(%d*)%s")
localnowx=tonumber(mousenowx)-abstlx
localnowy=tonumber(mousenowy)-abstly
--END CLICK CALCULATIONS #################################
return localx,localy,localnowx,localnowy
end--function

the numbers that appear are the coordinates of the bottom left corner of the box
the box is a conky cycle behind the text which is why you get the drag delay

next is to find a way to save the settings so that next time conky is launched the box appears where it was last put
probably just write the coordinates to a text file then have the script read the file on startup

Last edited by mrpeachy (2012-07-01 19:33:03)

Offline

Be excellent to each other!

#277 2012-07-02 16:29:20

falldown
#! Samurai
Registered: 2011-09-01
Posts: 1,727

Re: interactive conky

Very cool Peachy.
I will check it out later today.

Offline

#278 2012-07-04 20:45:55

arclance
#! Die Hard
Registered: 2012-03-29
Posts: 987

Re: interactive conky

mrpeachy wrote:

@arclance - i will take a look at your code

Have you had a chance to take a look at the code I posted yet?

Offline

#279 2012-07-04 21:58:23

mrpeachy
20% cooler
From: The Everfree Forest
Registered: 2009-11-08
Posts: 3,460

Re: interactive conky

arclance wrote:
mrpeachy wrote:

@arclance - i will take a look at your code

Have you had a chance to take a look at the code I posted yet?

To be honest I havn't put much thought into the xdotool code recently so i haven't tried you alternative yet.
i do think that it would be best to get conkyrc to be in charge of starting and stopping xdotool
probably just through execi with a large interval number (86400 or so)

i have the bash alias kfc which kills conky and xdotool

just had that idea about the movable conky and used the code i had at hand smile

Offline

#280 2012-07-04 22:19:45

arclance
#! Die Hard
Registered: 2012-03-29
Posts: 987

Re: interactive conky

mrpeachy wrote:
arclance wrote:
mrpeachy wrote:

@arclance - i will take a look at your code

Have you had a chance to take a look at the code I posted yet?

To be honest I havn't put much thought into the xdotool code recently so i haven't tried you alternative yet.
i do think that it would be best to get conkyrc to be in charge of starting and stopping xdotool
probably just through execi with a large interval number (86400 or so)

I don't think you can safely control xdotool using .conkyrc alone.
You could use lua_startup_hook and lua_shutdown_hook to start and stop xdotool when you want to.
If I remember correctly xdotool has a built in delay option you could use to allow the conky window to start before xdotool tries to connect to it.
I will see if I can find the xdotool man page online to find out what the exact command is since I can't use my computers at home until the power comes back on.
Edit:
The command I thought of does exist (sleep) but there is an even better one I had forgotten about.

search [options] pattern
.....
--sync 
    Block until there are results. This is useful when you are launching an application and want to wait until the application window is visible.

You could use it like this

function conky_start_xdotool()
    os.execute("xdotool search --sync --name 'conky' behave %@ mouse-click getmouselocation 2> /dev/null >> /tmp/xdo &")
    return ""
end --#

function conky_stop_xdotool()
    os.execute("pkill -f \"xdotool search --sync --name 'conky'\"")
    --os.execute("rm /tmp/xdo") --# if /tmp/xdo is locked while xdotool is running
    return ""
end --#

.conkyrc

......
lua_load #####
lua_startup_hook conky_start_xdotool()
lua_shutdown_hook conky_stop_xdotool()
TEXT

Since the xdotool is always running you may have problems deleting /tmp/xdo (I am not sure and I can't test it right now).
If that does happen you can just read the last line of /tmp/xdo to get the current position and delete the file when conky is closed by adding a command to conky_stop_xdotool().


The main issue I have with your current code is the use of "killall xdotool" because it is not safe since it can kill xdotool processes not started by the conky instance that created them.
I find that it tends to leave xdotool processes running if you kill conky for some reason as well.

Getting rid of the "findclient: " spam is just nice, it is only a cosmetic improvement for people who start conky in a terminal.

Last edited by arclance (2012-07-04 22:42:34)

Offline

#281 2012-07-17 19:18:53

arclance
#! Die Hard
Registered: 2012-03-29
Posts: 987

Re: interactive conky

Okay I tested what I proposed in my previous post and with a few modifications I got it working.

This will start a xdotool when conky starts and leave it running until the .conkyrc is reloaded or the conky process is killed.

If the .conkyrc is reloaded the xdotool process will be restarted by conky after it is killed.

/tmp/xdo will be removed when conky is killed.

stderr output from xdotool is sent to /dev/null.
    This gets rid of the "findclient: number" spam in the terminal and is needed for these changes to work.

If you want to run more than one conky with the button script give each one a unique "own_window_title" and have them write to different "/tmp/file_name" files by changing "tempFileName".

Here is the lua I came up with.

require 'cairo'

if tonumber(conky_parse('${updates}')) < 2 then --# don't clear buttons table if reloading lua script
    main_start = 1-- this starts the clickfunction
    buttons = {}--this table initially holds the values from the buttons
    conkyWindowTitle = "button_example" --# the title of the conky window (own_window_title) to make it easier to configure
    tempFileName = "xdo" --# the name of the temporary file to store mouse click locations in (makes configuring for use in more than one conky easier)
    abstlx = nil
    s = nil
    abstly = nil
end --# if tonumber(conky_parse('${updates}')) < 2 then

function conky_main()
    if conky_window == nil then return end
    local cs = cairo_xlib_surface_create(conky_window.display, conky_window.drawable, conky_window.visual, conky_window.width, conky_window.height)
    local cr = cairo_create(cs)
    local localx,localy,localnowx,localnowy = clickfunction()--this line activates the clickfunction and sets the click coordinates
    --#################################
    --###### Setup Buttons Here #######
    --#################################
    cairo_destroy(cr)
    cairo_surface_destroy(cs)
    cr = nil
    cs = nil
    conky_run_last()
    local gcollect = collectgarbage ("collect") --# memory police
end --# function conky_main()

function conky_start_xdotool()
    os.execute("pkill -f \"xdotool search --sync --name "..conkyWindowTitle.."\"")
    local f = io.open("/tmp/"..tempFileName,"w")
    f:write("x:0 y:0\n")
    f:close()
    f = nil
    os.execute("xdotool search --sync --name '"..conkyWindowTitle.."' behave %@ mouse-click getmouselocation 2> /dev/null >> /tmp/xdo &")
end --# function conky_start_xdotool()

function conky_stop_xdotool()
    os.execute("pkill -f \"xdotool search --sync --name "..conkyWindowTitle.."\"")
    os.execute("rm /tmp/"..tempFileName)
end --# function conky_stop_xdotool()

function clickfunction()
    --start click logging and calculations ##########################################
    if main_start == 1 then--run at script start 
        local f = io.popen("xwininfo -name '"..conkyWindowTitle.."' | grep 'Absolute'")
        local geometry = f:read("*a")
        f:close()
        f = nil
        local geometry = string.gsub(geometry,"[\n]","")
        s,f,abstlx = string.find(geometry,"X%p%s*(%p*%d*)")
        s,f,abstly = string.find(geometry,"Y%p%s*(%p*%d*)")
        main_start = nil
    end--if click_start=1 ######################################
    --click calculations #################################
    local f = io.popen("tail --lines=1 /tmp/"..tempFileName)
    local click = f:read("*a")
    f:close()
    f = nil
    if ((click == nil) or (click == "")) then click = "x:0 y:0 " end
    local s,f,mousex = string.find(click,"x%p(%d*)")
    local s,f,mousey = string.find(click,"y%p(%d*)")
    local localx = tonumber(mousex)-abstlx
    local localy = tonumber(mousey)-abstly
    --get now location
    local f = io.popen("xdotool getmouselocation 2> /dev/null")
    local mousenow = f:read("*a")
    f:close()
    f = nil
    local s,f,mousenowx = string.find(mousenow,"x%p(%d*)%s")
    local s,f,mousenowy = string.find(mousenow,"y%p(%d*)%s")
    local localnowx = tonumber(mousenowx)-abstlx
    local localnowy = tonumber(mousenowy)-abstly
    --END CLICK CALCULATIONS #################################
    return localx,localy,localnowx,localnowy
end --# function clickfunction()

function conky_run_last()
    local f = io.open("/tmp/"..tempFileName,"w")
    f:write("x:0 y:0\n")
    f:close()
    f = nil
end --# function conky_run_last()

The necessary part of the .conkyrc

own_window yes
own_window_class button_example
own_window_type normal
own_window_title button_example
own_window_hints undecorated,below,sticky,skip_taskbar,skip_pager

lua_load button_example.lua
lua_draw_hook_pre main
lua_startup_hook start_xdotool
lua_shutdown_hook stop_xdotool

This line could probably be done a little faster in lua since the file should only be two lines long, maybe a few more if you click several times per update.

local f = io.popen("tail --lines=1 /tmp/"..tempFileName)

I doubt my method of

local f = io.open("/tmp/"..tempFileName,"r")
local fileContents = f:read("*a")
local splitFile = assert(loadstring("return {'"..(fileContents:gsub("\n","','")).."'}"))()
local lastLine = splitFile[#splitFile]
f:close()
f = nil

is any faster for such a short file.

Other methods involve "for" loops and string.find() or
"while" or "until" loops and read("*l").

--# read last line with :read("*l)
local f = io.open("/tmp/"..tempFileName,"r")
local nextLine = f:read("*l")
local lastLine = nil
repeat
    lastLine = nextLine
    nextLine = f:read("*l")
until ((nextLine == "") or (nextLine == nil))
f:close()
f = nil

Last edited by arclance (2012-07-17 19:55:02)

Offline

#282 2012-07-18 00:17:14

mrpeachy
20% cooler
From: The Everfree Forest
Registered: 2009-11-08
Posts: 3,460

Re: interactive conky

thanks arclance
i will use this the next time im writing an interactive conky

do you by any chance know why the file xdotool writes to grows to multiple lines rather than the new info overwriting the old every time?

i thought that  ">" should overwrite and ">>" append... but in this case it doesnt seem matter if you use ">" or ">>" the file gets appended

Offline

#283 2012-07-18 00:30:28

arclance
#! Die Hard
Registered: 2012-03-29
Posts: 987

Re: interactive conky

It does that because the xdotool process never stops so it is appending to what it thinks is the same unaltered text file.

But at the end of every update the file is overwritten with
"x:0 y:0\n"
so the button does not fire every update until you click somewhere else.

Since xdotool has not stopped running it just appends each new line from stdout to the file like it normally would.


I also fixed a crash that happens if the xdotool log file exists but is empty for some reason when it is read by clickfunction().

I changed this line

if click == nil then click = "x:0 y:0 " end

to this

if ((click == nil) or (click == "")) then click = "x:0 y:0 " end

so that an empty file is treated the same as a missing file.

I noticed that when I was changing the io.open() to io.popen().
I suspect it was the cause of the "attempted to perform arithmatic on a nil value errors" I got from time to time.
It probably happened when xdotool was slow in starting up on one update and had not written anything to the log file yet.

Offline

#284 2012-07-19 03:19:41

arclance
#! Die Hard
Registered: 2012-03-29
Posts: 987

Re: interactive conky

I got another "attempt to perform arithmetic on a nil value" error today so I have not found the cause yet.

This is the line that has been causing the error.

local localnowx = tonumber(mousenowx)-abstlx

I has been happening to me every once in a while for a long time but I had not tired to figure out what was causing it before.

I found another possible cause of the crash and added a fix for it.
If this line

local f = io.popen("xdotool getmouselocation 2> /dev/null")

does not return anything for some reason it could have caused the crash.

Here is the clickfunction() with a check for that possibility added.

function clickfunction()
    --start click logging and calculations ##########################################
    local s = nil
    if main_start == 1 then--run at script start 
        local f = io.popen("xwininfo -name '"..conkyWindowTitle.."' | grep 'Absolute'")
        local geometry = f:read("*a")
        f:close()
        f = nil
        local geometry = string.gsub(geometry,"[\n]","")
        s,f,abstlx = string.find(geometry,"X%p%s*(%p*%d*)")
        s,f,abstly = string.find(geometry,"Y%p%s*(%p*%d*)")
        main_start = nil
    end--if click_start=1 ######################################
    --click calculations #################################
    local f = io.popen("tail --lines=1 /tmp/"..tempFileName)
    local click = f:read("*a")
    f:close()
    f = nil
    local mousex = nil
    local mousey = nil
    if ((click == nil) or (click == "")) then --click = "x:0 y:0 " end
        print("error: could not read xdotool logfile")
        mousex = "0"
        mousey = "0"
    else
        s,f,mousex = string.find(click,"x%p(%d*)")
        s,f,mousey = string.find(click,"y%p(%d*)")
    end --# if ((click == nil) or (click == "")) then
    local localx = tonumber(mousex)-abstlx
    local localy = tonumber(mousey)-abstly
    --get now location
    local f = io.popen("xdotool getmouselocation 2> /dev/null")
    local mousenow = f:read("*a")
    f:close()
    f = nil
    local mousenowx = nil
    local mousenowy = nil
    if ((mousenow == nil) or (mousenow == "")) then
        print("error: could not get mouse location")
        mousenowx = "0"
        mousenowy = "0"
    else
        s,f,mousenowx = string.find(mousenow,"x%p(%d*)%s")
        s,f,mousenowy = string.find(mousenow,"y%p(%d*)%s")
    end --# if ((mousenow == nil) or (mousenow == "")) then
    local localnowx = tonumber(mousenowx)-abstlx
    local localnowy = tonumber(mousenowy)-abstly
    --END CLICK CALCULATIONS #################################
    return localx,localy,localnowx,localnowy
end --# function clickfunction()

I also added an error message if the xdotool log file could not be read or was empty.

I made this change in my script so that if it happens again I will know what variable caused the crash.

local localnowx = assert(tonumber(mousenowx)-abstlx, ("mousenowx: '"..tostring(mousenowx).."' abstlx: '"..tostring(abstlx).."'"))

Offline

#285 2012-07-19 20:21:43

arclance
#! Die Hard
Registered: 2012-03-29
Posts: 987

Re: interactive conky

arclance wrote:

I found another possible cause of the crash and added a fix for it.
If this line

local f = io.popen("xdotool getmouselocation 2> /dev/null")

does not return anything for some reason it could have caused the crash.

That definitely is happening I just got the error message I setup for it today.

error: could not get mouse location

Offline

#286 2012-07-20 14:38:10

arclance
#! Die Hard
Registered: 2012-03-29
Posts: 987

Re: interactive conky

I found another crash condition and fixed it.
Sometimes xdotool returns

Command failed.

from this line.

local f = io.popen("tail --lines=1 /tmp/"..tempFileName)

To fix this just change

if ((click == nil) or (click == "")) then

to

if ((click == nil) or (click == "") or (click:gsub("\n","") == "Command failed.")) then

or use this if you want more detailed failure messages use this.

if ((click == nil) or (click == "")) then
        print("error: could not read xdotool logfile")
        mousex = "0"
        mousey = "0"
    elseif (click:gsub("\n","") == "Command failed.") then
        print("error: xdotool error")
        mousex = "0"
        mousey = "0"
    else
        s,f,mousex = string.find(click,"x%p(%d*)")
        s,f,mousey = string.find(click,"y%p(%d*)")
    end --# if ((click == nil) or (click == "")) then

Offline

#287 2012-07-20 23:52:49

mrpeachy
20% cooler
From: The Everfree Forest
Registered: 2009-11-08
Posts: 3,460

Re: interactive conky

while i like the idea of using the new start/shutdown lua settings in conky to start and stop xdotool
i think i have a simpler way to launch xdotool so that it is only run once but can recognise multiple conky windows and write clicks to a single file

conky_start.sh

#!/bin/bash

conky -c ~/conky_start/conky_start &
sleep 2 &&
xdotool search --sync --classname conky behave %@ mouse-click getmouselocation >> /home/mcdowall/Desktop/xdo.txt

i think that by searching for

classname conky

xdotool will recognize multiple conky windows, then each conky will have its individual own_window_title that its lua script will use to get the coordinates from xwininfo
(havn't tested this yet)

then a similar shutdown script
conky_stop.sh

#!/bin/bash

pkill -f \"xdotool search  --sync --classname conky\"
pkill -f conky

Offline

#288 2012-07-21 00:00:44

mrpeachy
20% cooler
From: The Everfree Forest
Registered: 2009-11-08
Posts: 3,460

Re: interactive conky

ive been working on simplifying button generation and have come up with this (still testing it out)

https://dl.dropbox.com/u/19008369/click_conky.tar.gz

it has 2 modes of operation...
MODE 1 setup in the lua script

in conkyrc you run like this

lua_load ~/conky_start/easyclick.lua
lua_draw_hook_pre buttonmain

TEXT

then you go to the lua script and edit to add buttons and set what those buttons do (lots and lots of options there!)
almost all options have a default so you dont have to specify them all, only the ones you need

MODE 2 - setup in conkyrc code
i have a test script like this

lua_load ~/conky_start/easyclick.lua
#lua_draw_hook_pre buttonmain

template1 ${lua button {btype=1,bname="conkybutton1",blx_off=5,bly_off=100,bw_off=70,bh_off=30,draw=1,dfcol_off=0x0000ff,dfcol_on=0x00ffff,text=1,txt_off="click me"}}

TEXT
${cpu cpu0}





                          ${if_match ${template1} == 1} button is on ${else} button is off ${endif}

again, only need to set the variables you need
i set the button up as a template (as the setup can get quite long)
then using an if_match in conky (the function returns a 1 if button is on and  if off) i can control things in the conky code

im starting conky and xdotool using a startup script as in my post above

this is the second mode in action...needs a little bit of bug hunting big_smile
http://youtu.be/tJpOk-KaHjQ

Last edited by mrpeachy (2012-07-21 00:15:50)

Offline

#289 2012-07-21 00:05:58

arclance
#! Die Hard
Registered: 2012-03-29
Posts: 987

Re: interactive conky

mrpeachy wrote:

while i like the idea of using the new start/shutdown lua settings in conky to start and stop xdotool
i think i have a simpler way to launch xdotool so that it is only run once but can recognise multiple conky windows and write clicks to a single file

That will probably not work very well with more than one conky process since you need to overwrite the file with "x:0 y:0\n" at the end of every conky update so that one click only activates the button one time.

If you are running multiple conkys they will not all read the file at the same time so you are likely to get a race condition where one conky has blanked the file before another can see the click.

You could also have the file reset come at the wrong time and end up with one click activating the button more than once.

That's what happened when I tried removing conky_run_last.
The button activated every update until I clicked somewhere else.

If you use conkys with different update_intervals this will absolutely happen.

You also have the issue that you are making a text file that grows every time you click your mouse on a conky.
The file could get large if you click your conky often and have your computer on for long periods of time.

Last edited by arclance (2012-07-21 00:10:02)

Offline

#290 2012-07-21 00:14:58

mrpeachy
20% cooler
From: The Everfree Forest
Registered: 2009-11-08
Posts: 3,460

Re: interactive conky

^hmmm
i'll have to test it out and see what happens

Offline

#291 2012-07-21 00:19:57

arclance
#! Die Hard
Registered: 2012-03-29
Posts: 987

Re: interactive conky

I tried that xdotool command with my three conkys and can confirm that xdotool does return clicks for all three of them with different window ids.

I still think the buttons will have timing issues if you do it that way though.

I would add "2> /dev/null" to your xdotool line to keep the log file size as small as possible because of the findclient lines.

findclient: 13654293
findclient: 13654293
findclient: 13654289
x:888 y:978 screen:0 window:13654289

It might work if you have the script check the window number and only do the button calculations if it matches the window number of that conky.
You would also need to use a variable to tell conky_run_last if it should overwrite the file or not (only overwrite if a click was registered in that conky window).

That probably would not make all timing issues go away but it would make them better.

Last edited by arclance (2012-07-21 00:30:21)

Offline

#292 2012-07-21 00:49:03

arclance
#! Die Hard
Registered: 2012-03-29
Posts: 987

Re: interactive conky

arclance wrote:

It might work if you have the script check the window number and only do the button calculations if it matches the window number of that conky.
You would also need to use a variable to tell conky_run_last if it should overwrite the file or not (only overwrite if a click was registered in that conky window).

That probably would not make all timing issues go away but it would make them better.

Something like this though it's not finished yet.
I still need a way to get the xdotool window number in "if main_start == 1".

function clickfunction()
    --start click logging and calculations ##########################################
    local s = nil
    if main_start == 1 then--run at script start 
        local f = io.popen("xwininfo -name '"..conkyWindowTitle.."' | grep 'Absolute'")
        local geometry = f:read("*a")
        f:close()
        f = nil
        local geometry = string.gsub(geometry,"[\n]","")
        s,f,abstlx = string.find(geometry,"X%p%s*(%p*%d*)")
        s,f,abstly = string.find(geometry,"Y%p%s*(%p*%d*)")
        --# get xdotool_window_number here
        main_start = nil
    end--if click_start=1 ######################################
    --click calculations #################################
    local f = io.popen("tail --lines=1 /tmp/"..tempFileName)
    local click = f:read("*a")
    f:close()
    f = nil
    local localx
    local localy
    local localnowx
    local localnowy
    local reset_xdotool_log = false
    if string.find(click, xdotool_window_number) ~= nil then
        reset_xdotool_log = true
        local mousex = nil
        local mousey = nil
        if ((click == nil) or (click == "")) then
            print("error: could not read xdotool logfile")
            mousex = "0"
            mousey = "0"
        elseif (click:gsub("\n","") == "Command failed.") then
            print("error: xdotool error")
            mousex = "0"
            mousey = "0"
        else
            s,f,mousex = string.find(click,"x%p(%d*)")
            s,f,mousey = string.find(click,"y%p(%d*)")
        end --# if ((click == nil) or (click == "")) then
        localx = tonumber(mousex)-abstlx
        localy = tonumber(mousey)-abstly
        --get now location
        local f = io.popen("xdotool getmouselocation 2> /dev/null")
        local mousenow = f:read("*a")
        f:close()
        f = nil
        local mousenowx = nil
        local mousenowy = nil
        if ((mousenow == nil) or (mousenow == "")) then
            print("error: could not get mouse location")
            mousenowx = "0"
            mousenowy = "0"
        else
            s,f,mousenowx = string.find(mousenow,"x%p(%d*)%s")
            s,f,mousenowy = string.find(mousenow,"y%p(%d*)%s")
        end --# if ((mousenow == nil) or (mousenow == "")) then
        localnowx = tonumber(mousenowx)-abstlx
        localnowy = tonumber(mousenowy)-abstly
    else
        localx = 0
        localy = 0
        local f = io.popen("xdotool getmouselocation 2> /dev/null")
        local mousenow = f:read("*a")
        f:close()
        f = nil
        local mousenowx = nil
        local mousenowy = nil
        if ((mousenow == nil) or (mousenow == "")) then
            print("error: could not get mouse location")
            mousenowx = "0"
            mousenowy = "0"
        else
            s,f,mousenowx = string.find(mousenow,"x%p(%d*)%s")
            s,f,mousenowy = string.find(mousenow,"y%p(%d*)%s")
        end --# if ((mousenow == nil) or (mousenow == "")) then
        localnowx = tonumber(mousenowx)-abstlx
        localnowy = tonumber(mousenowy)-abstly
    end --# if string.find(click, xdotool_window_number) ~= nil then
    --END CLICK CALCULATIONS #################################
    return localx,localy,localnowx,localnowy,reset_xdotool_log
end --# function clickfunction()

function conky_run_last(reset_xdotool_log)
    if reset_xdotool_log == true then
        local f = io.open("/tmp/"..tempFileName,"w")
        f:write("x:0 y:0 screen:0 window:0\n")
        f:close()
        f = nil
    end --# if reset_xdotool_log == true then
end --# function conky_run_last()

Last edited by arclance (2012-07-21 00:54:46)

Offline

#293 2012-07-21 01:21:05

arclance
#! Die Hard
Registered: 2012-03-29
Posts: 987

Re: interactive conky

arclance wrote:

I still need a way to get the xdotool window number in "if main_start == 1".

It looks like this is not possible because "behave %@ mouse-click getmouselocation" returns a different number from the commands that do not use the mouse.

Using that I get

x:387 y:711 screen:0 window:13660277

But "xdotool search --name 'system_Conky'" returns "29360129".

"xwininfo -name 'system_Conky'" agrees with this.
It gives "0x1c00001" in hex which is "29360129" in dec.

Last edited by arclance (2012-07-21 02:05:44)

Offline

#294 2012-07-21 02:56:17

mrpeachy
20% cooler
From: The Everfree Forest
Registered: 2009-11-08
Posts: 3,460

Re: interactive conky

i had to change some code for the button script i posted earlier when i realized that the xdotool commands were being activated every cycle by every button... which was bad
https://dl.dropbox.com/u/19008369/click_conky.tar.gz

now in conkyrc you need this

lua_load ~/conky_start/easyclick.lua
lua_draw_hook_pre conkyclick #so that click location is only generated once per cycle rather than one per button per cycle

template1 ${lua button {btype=1,bname="conkybutton1",blx_off=5,bly_off=100,bw_off=70,bh_off=30,draw=1,dfcol_off=0x0000ff,dfcol_on=0x00ffff,text=1,txt_off="click me"}}

TEXT
${cpu cpu0}





                          ${if_match ${template1} == 1} button is on ${else} button is off ${endif}

this one is a work in progress big_smile

Last edited by mrpeachy (2012-07-21 02:56:50)

Offline

#295 2012-07-22 04:32:04

arclance
#! Die Hard
Registered: 2012-03-29
Posts: 987

Re: interactive conky

arclance wrote:
arclance wrote:

I still need a way to get the xdotool window number in "if main_start == 1".

It looks like this is not possible because "behave %@ mouse-click getmouselocation" returns a different number from the commands that do not use the mouse.

Using that I get

x:387 y:711 screen:0 window:13660277

But "xdotool search --name 'system_Conky'" returns "29360129".

"xwininfo -name 'system_Conky'" agrees with this.
It gives "0x1c00001" in hex which is "29360129" in dec.

I figured out how to get the number that is reported by "getmouselocation".
You can get it like this.

xwininfo -int -tree -name 'system_Conky' | grep 'Parent'

Which returns a line like this.

  Parent window id: 13549272 (has no name)

Which matches the number returned by

xdotool search --sync --classname conky behave %@ mouse-click getmouselocation 2> /dev/null

x:204 y:566 screen:0 window:13549272

I am too tired to work it into my example tonight but I will try to tomorrow.

Last edited by arclance (2012-07-22 04:32:39)

Offline

#296 2012-07-22 18:27:25

arclance
#! Die Hard
Registered: 2012-03-29
Posts: 987

Re: interactive conky

arclance wrote:

I figured out how to get the number that is reported by "getmouselocation".
....
I am too tired to work it into my example tonight but I will try to tomorrow.

Ok here is a complete example of how to get each conky to recognize if the click was in its window and only reset the log file if it was the window clicked on.

require 'cairo'

if tonumber(conky_parse('${updates}')) < 2 then --# don't clear buttons table if reloading lua script
    main_start = 1-- this starts the clickfunction
    buttons = {}--this table initially holds the values from the buttons
    conkyWindowTitle = "button_example" --# the title of the conky window (own_window_title) to make it easier to configure
    tempFileName = "xdo" --# the name of the temporary file to store mouse click locations in (makes configuring for use in more than one conky easier)
    abstlx = nil
    abstly = nil
    xdotool_window_number = nil
end --# if tonumber(conky_parse('${updates}')) < 2 then

function conky_main()
    if conky_window == nil then return end
    local cs = cairo_xlib_surface_create(conky_window.display, conky_window.drawable, conky_window.visual, conky_window.width, conky_window.height)
    local cr = cairo_create(cs)
    local localx,localy,localnowx,localnowy,reset_xdotool_log = clickfunction()--this line activates the clickfunction and sets the click coordinates
    --#################################
    --###### Setup Buttons Here #######
    --#################################
    cairo_destroy(cr)
    cairo_surface_destroy(cs)
    cr = nil
    cs = nil
    conky_run_last(reset_xdotool_log)
    local gcollect = collectgarbage ("collect") --# memory police
end --# function conky_main()

function clickfunction()
    --start click logging and calculations ##########################################
    local s = nil
    if main_start == 1 then--run at script start 
        local f = io.popen("xwininfo -name '"..conkyWindowTitle.."' | grep 'Absolute'")
        local geometry = f:read("*a")
        f:close()
        f = nil
        local geometry = string.gsub(geometry,"[\n]","")
        s,f,abstlx = string.find(geometry,"X%p%s*(%p*%d*)")
        s,f,abstly = string.find(geometry,"Y%p%s*(%p*%d*)")
        --# get xdotool_window_number here
        local f = io.popen("xwininfo -int -tree -name '"..conkyWindowTitle.."' | grep 'Parent'")
        local winData = f:read("*l")
        f:close()
        f = nil
        s,f,xdotool_window_number = string.find(winData,"(%d+)%s")
        main_start = nil
    end--if click_start=1 ######################################
    --click calculations #################################
    local f = io.popen("tail --lines=1 /tmp/"..tempFileName)
    local click = f:read("*a")
    f:close()
    f = nil
    local localx
    local localy
    local localnowx
    local localnowy
    local reset_xdotool_log = false
    local mousex = nil
    local mousey = nil
    if ((click == nil) or (click == "")) then
        print("error: could not read xdotool logfile")
        mousex = "0"
        mousey = "0"
    elseif (click:gsub("\n","") == "Command failed.") then
        print("error: xdotool error")
        mousex = "0"
        mousey = "0"
    else
        if string.find(click, xdotool_window_number) ~= nil then
            s,f,mousex = string.find(click,"x%p(%d*)")
            s,f,mousey = string.find(click,"y%p(%d*)")
            reset_xdotool_log = true
        else
            print("debug: click not in this window")
            mousex = "0"
            mousey = "0"
        end --# if string.find(click, xdotool_window_number) ~= nil then
    end --# if ((click == nil) or (click == "")) then
    localx = tonumber(mousex)-abstlx
    localy = tonumber(mousey)-abstly
    --get now location
    local f = io.popen("xdotool getmouselocation 2> /dev/null")
    local mousenow = f:read("*a")
    f:close()
    f = nil
    local mousenowx = nil
    local mousenowy = nil
    if ((mousenow == nil) or (mousenow == "")) then
        print("error: could not get mouse location")
        mousenowx = "0"
        mousenowy = "0"
    else
        s,f,mousenowx = string.find(mousenow,"x%p(%d*)%s")
        s,f,mousenowy = string.find(mousenow,"y%p(%d*)%s")
    end --# if ((mousenow == nil) or (mousenow == "")) then
    localnowx = tonumber(mousenowx)-abstlx
    localnowy = tonumber(mousenowy)-abstly
    --END CLICK CALCULATIONS #################################
    return localx,localy,localnowx,localnowy,reset_xdotool_log
end --# function clickfunction()

function conky_run_last(reset_xdotool_log)
    if reset_xdotool_log == true then
        local f = io.open("/tmp/"..tempFileName,"w")
        f:write("x:0 y:0 screen:0 window:0\n")
        f:close()
        f = nil
    end --# if reset_xdotool_log == true then
end --# function conky_run_last()

I have not set up a conky to test it on yet so let me know what you think of it.
Edit: Simplified window check.
Edit2: I tested it on a single conky using my old method of starting xdotool and it works.
It still needs testing with your new way of starting xdotool and with more than one conky at a time.

Last edited by arclance (2012-07-22 18:38:03)

Offline

#297 2012-07-22 18:37:51

mrpeachy
20% cooler
From: The Everfree Forest
Registered: 2009-11-08
Posts: 3,460

Re: interactive conky

interesting, good idea to check on window number before the file is reset

ive tried that "2> /dev/null" line, but im still getting the "findclient" messages in the terminal
personally i dont mind that and it seems you have been having to work around some problems from implementing it

Offline

#298 2012-07-22 18:49:29

arclance
#! Die Hard
Registered: 2012-03-29
Posts: 987

Re: interactive conky

Yes it may resolve the issues I brought up before at least as long as you are running a sane number of conkys with buttons.

Removing the "findclient" lines did not cause any new problems to work around, I just got rid of them to simplify parsing of the xdotool log when it is left to run constantly.

Here is how I use the "2> /dev/null" line, maybe the order you put it in makes a difference.

xdotool search --sync --name 'system_Conky' behave %@ mouse-click getmouselocation 2> /dev/null >> /tmp/xdo
x:3470 y:973 screen:0 window:17853980

Here is what I get with the same command without the "2> /dev/null".

xdotool search --sync --name 'system_Conky' behave %@ mouse-click getmouselocation >> /tmp/xdo
findclient: 17853984
findclient: 17853984
findclient: 17853980
x:3357 y:961 screen:0 window:17853980

The findclient lines should go away whenever a new version of xdotool is released since they are caused by leftover debugging lines that have already been removed in the git version.

I am up the point in moving my weather script to be displayed with lua that I am adding buttons to it so I should be able to test it on multiple conkys in the next few days.

Last edited by arclance (2012-07-22 18:52:19)

Offline

#299 2012-07-22 19:28:57

arclance
#! Die Hard
Registered: 2012-03-29
Posts: 987

Re: interactive conky

Ok I tested my new example with xdotool running this way.

xdotool search --sync --classname 'conky' behave %@ mouse-click getmouselocation 2> /dev/null >> /tmp/xdo

You do have to start this after all your conkys start or it won't detect them and if you restart any of them you have to restart the xdotool process as well.

It works so far, but I had to change when conky_run_last() is run to make the buttons only work once per click.

I made conky_run_last() (now button_run_last()) run at the end of clickfunction() so the file is overwritten immediately after a click in that window has been detected.

I suspect this was due to the file being locked when I tired to overwrite it due to my weather conky trying to read it at the same time.

require 'cairo'

if tonumber(conky_parse('${updates}')) < 2 then --# don't clear buttons table if reloading lua script
    main_start = 1-- this starts the clickfunction
    buttons = {}--this table initially holds the values from the buttons
    conkyWindowTitle = "button_example" --# the title of the conky window (own_window_title) to make it easier to configure
    tempFileName = "xdo" --# the name of the temporary file to store mouse click locations in (makes configuring for use in more than one conky easier)
    abstlx = nil
    abstly = nil
    xdotool_window_number = nil
end --# if tonumber(conky_parse('${updates}')) < 2 then

function conky_main()
    if conky_window == nil then return end
    local cs = cairo_xlib_surface_create(conky_window.display, conky_window.drawable, conky_window.visual, conky_window.width, conky_window.height)
    local cr = cairo_create(cs)
    local localx,localy,localnowx,localnowy = clickfunction()--this line activates the clickfunction and sets the click coordinates
    --#################################
    --###### Setup Buttons Here #######
    --#################################
    cairo_destroy(cr)
    cairo_surface_destroy(cs)
    cr = nil
    cs = nil
    local gcollect = collectgarbage ("collect") --# memory police
end --# function conky_main()

function clickfunction()
    --start click logging and calculations ##########################################
    local s = nil
    if main_start == 1 then--run at script start 
        local f = io.popen("xwininfo -name '"..conkyWindowTitle.."' | grep 'Absolute'")
        local geometry = f:read("*a")
        f:close()
        f = nil
        local geometry = string.gsub(geometry,"[\n]","")
        s,f,abstlx = string.find(geometry,"X%p%s*(%p*%d*)")
        s,f,abstly = string.find(geometry,"Y%p%s*(%p*%d*)")
        --# get xdotool_window_number here
        local f = io.popen("xwininfo -int -tree -name '"..conkyWindowTitle.."' | grep 'Parent'")
        local winData = f:read("*l")
        f:close()
        f = nil
        s,f,xdotool_window_number = string.find(winData,"(%d+)%s")
        main_start = nil
    end--if click_start=1 ######################################
    --click calculations #################################
    local f = io.popen("tail --lines=1 /tmp/"..tempFileName)
    local click = f:read("*a")
    f:close()
    f = nil
    local localx
    local localy
    local localnowx
    local localnowy
    local reset_xdotool_log = false
    local mousex = nil
    local mousey = nil
    if ((click == nil) or (click == "")) then
        print("error: could not read xdotool logfile")
        mousex = "0"
        mousey = "0"
    elseif (click:gsub("\n","") == "Command failed.") then
        print("error: xdotool error")
        mousex = "0"
        mousey = "0"
    else
        if string.find(click, xdotool_window_number) ~= nil then
            s,f,mousex = string.find(click,"x%p(%d*)")
            s,f,mousey = string.find(click,"y%p(%d*)")
            reset_xdotool_log = true
        else
            print("debug: click not in this window")
            mousex = "0"
            mousey = "0"
        end --# if string.find(click, xdotool_window_number) ~= nil then
    end --# if ((click == nil) or (click == "")) then
    localx = tonumber(mousex)-abstlx
    localy = tonumber(mousey)-abstly
    --get now location
    local f = io.popen("xdotool getmouselocation 2> /dev/null")
    local mousenow = f:read("*a")
    f:close()
    f = nil
    local mousenowx = nil
    local mousenowy = nil
    if ((mousenow == nil) or (mousenow == "")) then
        print("error: could not get mouse location")
        mousenowx = "0"
        mousenowy = "0"
    else
        s,f,mousenowx = string.find(mousenow,"x%p(%d*)%s")
        s,f,mousenowy = string.find(mousenow,"y%p(%d*)%s")
    end --# if ((mousenow == nil) or (mousenow == "")) then
    localnowx = tonumber(mousenowx)-abstlx
    localnowy = tonumber(mousenowy)-abstly
    button_run_last(reset_xdotool_log)
    --END CLICK CALCULATIONS #################################
    return localx,localy,localnowx,localnowy
end --# function clickfunction()

function button_run_last(reset_xdotool_log)
    if reset_xdotool_log == true then
        local f = io.open("/tmp/"..tempFileName,"w")
        f:write("x:0 y:0 screen:0 window:0\n")
        f:close()
        f = nil
    end --# if reset_xdotool_log == true then
end --# function conky_run_last()

It really needs to be tested with multiple conkys setup with buttons to see if there are still timing issues in that case.

I think you may find that if your method does not work with more than two or three button conkys due to the timing issues growing rapidly as you increase the number of conkys trying to read the xdotool log file at the same time.

Last edited by arclance (2012-07-22 19:45:28)

Offline

Be excellent to each other!

#300 2012-07-22 20:22:12

arclance
#! Die Hard
Registered: 2012-03-29
Posts: 987

Re: interactive conky

I added a button to my weather conky that is for changing from a daily to hourly display.
acrBjSas.jpg
I seems to be working with the single xdotool process using "classname" but I do have to restart the xdotool process every time I restart one of my conkys.

The hourly setting does not do anything yet but the toggle button works.

Last edited by arclance (2012-07-22 20:24:36)

Offline

Board footer

Powered by FluxBB

Copyright © 2012 CrunchBang Linux.
Proudly powered by Debian. Hosted by Linode.
Debian is a registered trademark of Software in the Public Interest, Inc.
Server: acrobat

Debian Logo