You are not logged in.
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--functionthe 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
Very cool Peachy.
I will check it out later today.
Peachy's v9000 / Conky PitStop / My DA Page / VSIDO
Make it so....
Offline
@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
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 
Offline
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()
TEXTSince 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
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_xdotoolThis 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 = nilis 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 = nilLast edited by arclance (2012-07-17 19:55:02)
Offline
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
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 " endto this
if ((click == nil) or (click == "")) then click = "x:0 y:0 " endso 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
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)-abstlxI 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
I found another possible cause of the crash and added a fix for it.
If this linelocal 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 locationOffline
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 == "")) thento
if ((click == nil) or (click == "") or (click:gsub("\n","") == "Command failed.")) thenor 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 == "")) thenOffline
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.txti think that by searching for
classname conkyxdotool 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 conkyOffline
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
TEXTthen 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 
http://youtu.be/tJpOk-KaHjQ
Last edited by mrpeachy (2012-07-21 00:15:50)
Offline
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
^hmmm
i'll have to test it out and see what happens
Offline
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:13654289It 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
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
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:13660277But "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
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 
Last edited by mrpeachy (2012-07-21 02:56:50)
Offline
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:13660277But "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:13549272I 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
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
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
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:17853980Here 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:17853980The 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
Ok I tested my new example with xdotool running this way.
xdotool search --sync --classname 'conky' behave %@ mouse-click getmouselocation 2> /dev/null >> /tmp/xdoYou 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
I added a button to my weather conky that is for changing from a daily to hourly display.
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
Copyright © 2012 CrunchBang Linux.
Proudly powered by Debian. Hosted by Linode.
Debian is a registered trademark of Software in the Public Interest, Inc.