Some context:
I am writing a font-previewing application, and one of the things I have to do very often is change the size of the text. As you can see in the image, someone drags the "Size" slider, and the application has to change the size of all of those pieces of text.
NOTE:
keep in mind I am not using beautiful.load_font and these examples are happening in my own text element I wrote, NOT in "wibox/widget/textbox.lua". So no caching happens from there, and I don't do any caching of fonts myself currently.
Initially, I tried to write something like:
-- in my "draw" function which would be called every time someone would move
-- the "Size" slider:
local tf = self.family .. ' ' .. self.weight .. ' ' .. self.size
local new_desc = lgi.Pango.FontDescription.from_string(tf)
text_layout:set_font_description(new_desc)
cr:update_layout(self._text_layout)
cr:show_layout(self._text_layout)
Using this was very slow, down to about 10 - 30 fps as I moved my mouse on the "Size" slider. To try to make this faster, I thought about NOT setting the font description on the text_layout every time, but only set it once when the text element was created, and try to only change the size every time I had to redraw.
So I read the Pango docs, and tried this:
when the text element is created:
local ctx = lgi.PangoCairo.font_map_get_default():create_context()
local text_layout = lgi.Pango.Layout.new(ctx)
local typeface_description = font_family .. " " .. font_weight
local desc = lgi.Pango.FontDescription.from_string(typeface_description)
text_layout:set_font_description(desc)
local pango_attrs = lgi.Pango.AttrList.new()
local pango_size = lgi.Pango.AttrSize.new(font_size * lgi.Pango.SCALE)
lgi.Pango.AttrList.insert(pango_attrs, pango_size)
text_layout:set_attributes(pango_attrs)
self.pango_attrs = pango_attrs
In my "draw" function:
local pango_size = lgi.Pango.AttrSize.new(self.size * lgi.Pango.SCALE)
lgi.Pango.AttrList.change(self.pango_attrs, pango_size)
And when I do this, and use "Xephyr" for testing, The application works well until I start moving the "Size" knob. Then, as I move it, the application still works well for 1-3 seconds. Then, I get a blank screen, and I get this in my terminal:
kill: not enough arguments
kill: not enough arguments
Calling callback function on subscribed signal 'TimeChanged' failed: ./wonderful/bar.lua:148: Pango.Attribute: no `format'
Calling callback function on subscribed signal 'TimeChanged' failed: ./apps/RibbonPanel/LateForLunch/layout.lua:49: Pango.Attribute: no `format'
2022-11-20 09:06:50 E: awesome: signal_fatal:497: signal 11, dumping backtrace
awesome(backtrace_get+0x5f) [0x563e0a3984f2]
awesome(+0x1343e) [0x563e0a38243e]
/usr/lib/libc.so.6(+0x38a00) [0x7fbfdcaa3a00]
/usr/lib/libpango-1.0.so.0(pango_attribute_destroy+0xc) [0x7fbfdb10c36c]
/usr/lib/lua/5.1/lgi/corelgilua51.so(+0x12dc2) [0x7fbfdb386dc2]
/usr/lib/lua/5.1/lgi/corelgilua51.so(+0x132a8) [0x7fbfdb3872a8]
/usr/lib/libluajit-5.1.so.2(+0x9ef6) [0x7fbfdccb9ef6]
/usr/lib/libluajit-5.1.so.2(+0xfcd6) [0x7fbfdccbfcd6]
/usr/lib/libluajit-5.1.so.2(+0x16eac) [0x7fbfdccc6eac]
/usr/lib/libluajit-5.1.so.2(+0x174cd) [0x7fbfdccc74cd]
/usr/lib/libluajit-5.1.so.2(lua_pushstring+0x95) [0x7fbfdccd1955]
awesome(+0x1cc21) [0x563e0a38bc21]
/usr/lib/libluajit-5.1.so.2(+0x9ef6) [0x7fbfdccb9ef6]
/usr/lib/libluajit-5.1.so.2(lua_getfield+0xb1) [0x7fbfdccd7d51]
/usr/lib/lua/5.1/lgi/corelgilua51.so(lgi_marshal_access+0x2c) [0x7fbfdb38585c]
/usr/lib/libluajit-5.1.so.2(+0x9ef6) [0x7fbfdccb9ef6]
/usr/lib/libluajit-5.1.so.2(lua_pcall+0xb3) [0x7fbfdcccc873]
/usr/lib/lua/5.1/lgi/corelgilua51.so(+0x82ee) [0x7fbfdb37c2ee]
/usr/lib/libffi.so.8(+0x70d2) [0x7fbfdc7320d2]
/usr/lib/libffi.so.8(+0x7718) [0x7fbfdc732718]
/usr/lib/libglib-2.0.so.0(+0x560a2) [0x7fbfdd1bd0a2]
/usr/lib/libglib-2.0.so.0(g_main_context_dispatch+0x19b) [0x7fbfdd1bc87b]
/usr/lib/libglib-2.0.so.0(+0xac279) [0x7fbfdd213279]
/usr/lib/libglib-2.0.so.0(g_main_loop_run+0x6f) [0x7fbfdd1bbddf]
awesome(main+0x166c) [0x563e0a383eb0]
/usr/lib/libc.so.6(+0x23290) [0x7fbfdca8e290]
/usr/lib/libc.so.6(__libc_start_main+0x8a) [0x7fbfdca8e34a]
awesome(_start+0x25) [0x563e0a382045]
I decided to ask this because it seems to me like the error has something to do with pango_attribute_destroy. I know awesome is using "lgi", which also includes Pango, so my question is: Am I doing something wrong? Or is this a bug in another library like "lgi"?
Related
local RS = game:GetService("ReplicatedStorage")
local Event = Instance.new("RemoteEvent", RS)
Event.Name = "PunchEvent"
local function FiredEvent(Player)
local Character = game.Workspace:WaitForChild(Player.Name)
local Animation = RS:WaitForChild("Animations"):GetChildren()[math.random(1, #RS.Animations:GetChildren())]
print(Animation)
local RandomAnim = Character.Humanoid:LoadAnimation(Animation)
RandomAnim:Play()
local Damage = script.Damage:Clone()
if Animation.Name == "Right Arm" then
Damage.Parent = Character:WaitForChild("Right Arm")
end
Damage.Disabled = false
wait(1.4)
Damage:Destroy()
end
Event.OnServerEvent:Connect(FiredEvent)
The image is clickable
The first error in the output is probably not one to ignore, sounds like the animations asset is supposed to be loaded from somewhere remote, and it is not found.
Once you have resolved that error, if the timeout problem doesn't get resolved, go to the "Explorer" panel and make sure that there exists "Animations" child. The error you asked about means that it could not find that object in the hierarchy. So, make sure ReplicatedStorage has Animations under it in the explorer pane.
In programming, "yield" means stop, or in your case, wait. If you look at your output, the first error said that the animations failed to load. Since your code Waits for the animations to load, you are being warned that your code might (and probably will) wait forever, or infinitely, for the animations to load.
So I've been trying to configure my Awesome WM config (rc.lua) to detect if my IBM model M13 is connected to my laptop upon login/reset. This is to change what the modkey should be since the M13 doesn't have a super key.
The following code makes sense to me and changes modkey within the function being made for the awful.spawn.easy_async function, but after finishing the modkey changes back to Mod4.
modkey = "Mod4"
awful.spawn.easy_async(
"xinput list",
function(stdout, stderr, reason, code)
local msg = "Regular keyboard Modkey = Super"
-- Debug notification that shows that the modkey is
-- at its default for the superkey Mod4
naughty.notify({
text = modkey,
timeout =7
})
if code ~= 0 then
msg = "Missing xinput to see devices\nModkey = Super"
elseif stdout:match("CHESEN") == "CHESEN" then
-- CHESEN is my PS/2 to USB adapter
msg = "IBM M13 detected\nModkey = Alt"
modkey = "Mod1" -- Sets new modkey to Alt
end
-- Notification message
naughty.notify({
text = msg,
timeout =7
})
end
)
-- Debug notification to verify key but key goes back to Mod4
naughty.notify({
text = modkey,
timeout =7
})
The output can be seen here. It doesn't print the notifications in order but the prints of Mod 4 are both of the debug prints.
Notification Output
I don't use Lua much aside from changing my configs from time to time so I'm having difficulty understanding how my global variable modkey can be changed with out it resetting. Other methods I tried was to have the function defined as a function I called setModKey to be passed as a parameter to easy_async and I tried setting modkey using _G to set it as _G.modkey, but I end up getting the same result.
Am I missing something fundamental to Lua or is this affected by how Awesome WM utilizes Lua? Any help will be very appreciated.
Use io.popen instead of awful.spawn.easy_async. Yes, normally using io.popen is really not recommended, but here the following happens:
Awesome starts
You call easy_async to capture the output of xinput list
Since it is async, your config continues to be loaded, so e.g. all your keybindings are set
easy_async does its job and you set modkey to something else.
This means that any keybinding which will be defined from now on use the new modkey, but all already-existing keybindings are not modified by this. So, basically nothing happens.
And for your debugging calls to naughty.notify: The one after the function is triggered first and only then, later, the inner one triggers. So it does not go back, but instead you first show the old value and only later the new one.
I have a NodeMCU ESP8266 board running MicroPython. I'm running a web server on my ESP8266. This is my first IoT project based on one of these boards.
The below is a snippet of the code.
This is being executed within main.py. Every now and then, something causes the code to crash (perhaps timing and request based). When main.py exits, for whatever reason, I'm dropped back at the python CLI.
I'd like for the board to reset when this happens (if there isn't a better way).
What is the best method of restarting/reseting the ESP8266?
addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]
s = socket.socket()
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(addr)
s.listen(5)
print('listening on', addr)
while True:
cl, addr = s.accept()
print('client connected from', addr)
cl_file = cl.makefile('rwb', 0)
print("Request:")
while True:
line = cl_file.readline()
print("Line:" , line)
if not line or line == b'\r\n':
print("breaking")
break
if line == b'GET /active HTTP/1.1\r\n':
MicroPython has machine.reset() function to reset a board.
Python (not just MicroPython) uses exception handling to handle errors.
Combining the two, you can easily achieve what you want. For example:
a = 4
b = 2
try:
a / b
except:
machine.reset()
If in the code above you replace value of b with 0, your board will reset. If you think about it for a bit, you probably will find out that it doesn't make much sense - you don't want your board suddenly reset if you just divide by 0 by mistake or otherwise. There're got to be better ways to handle errors! Likewise, you may want to think about your own case and see if resetting the board is really the best choice. If you think that yes, that's fine, just always keep in mind that you programmed your board to suddenly reset. Otherwise, your next question here may be "My board suddenly resets! Why???" ;-)
It may be late for the original question, but the answer I am going to share might help other people. Consider it is not a final solution, but in many scenarios, it may save a day. You can explore your case.
The solution is using the internal scheduling function of MicroPython. since its execution is guaranteed, then its behavior can be used as a tool to mimic a functional watchdog.
Following code will run with given timers and threshold which can be customized in your case, and if the timer reaches its threshold, and the value of wd_buffer is not updated for that time, then the function might be called, and we repeat the process again.
So in order to prevent the ESP getting restarted in this case after 12 sec, you have to in someplace in your code, periodically (shorter than 12 sec or adjust the timer and threshold according to your need) update the value of the Global wd_buffer variable. Hope it helps.
# Simple WD - Global Variable
wd_feeder = 0
wd_buffer = 0
wd_counter = 0
wd_threshold = 4
def wd_checker(calledvalue):
print('watchdog is checking... feeder= {} buffer= {}'.format(wd_feeder, wd_buffer))
global wd_counter
global wd_buffer
global wd_feeder
if wd_feeder == wd_buffer:
print('state is suspicious ... counter is {} incrementing the counter'.format(wd_counter))
wd_counter += 1
else:
wd_counter = 0
wd_feeder = wd_buffer
if wd_counter == wd_threshold:
print('Counter is reached its threshold, following function will be called')
wd_feeder = wd_buffer = wd_counter = 0
machine.reset()
if __name__ == '__main__':
scheduler_wd = machine.Timer(-1)
scheduler_wd.init(period=3000, mode=machine.Timer.PERIODIC, callback=wd_checker)
you could add a while loop checking for the Flash Button (GPIO pin 0) like this:
import machine
pin = machine.Pin(0, machine.Pin.IN, machine.Pin.PULL_UP)
while pin.value():
print('Put your code here...')
print('..this will looping until the Flash button is pressed...')
print('...and then it continues here.')
You could execute your code (which should be outside of the main.py -> other file) from the boot or the main.py. if it drops out it should execute the following code, which could trigger a reset.
You may have to catch the error first.
I hope I helped
This code is for a modding engine, Unitale base on Unity Written in Lua
So I am trying to use a Boolean Variable in my script poseur.lua, so when certain conditions are met so I can pass it to the other script encounter.lua, where a engine Predefined functions is being uses to make actions happens base on the occurring moment.
I tried to read the engine documentation multiple times, follow the exact syntax of Lua's fonction like GetVar(), SetVar(), SetGobal(),GetGlobal().
Searching and google thing about the Language, post on the subreddit and Game Exchange and tried to solve it by myself for hours... I just can't do it and I can't understand why ?
I will show parts of my codes for each.
poseur:
-- A basic monster script skeleton you can copy and modify for your own creations.
comments = {"Smells like the work\rof an enemy stand.",
"Nidhogg_Warrior is posing like his\rlife depends on it.",
"Nidhogg_Warrior's limbs shouldn't\rbe moving in this way."}
commands = {"GREET", "JUMP", "FLIRT", "CRINGE"}
EndDialougue = {" ! ! !","ouiii"}
sprite = "poseur" --Always PNG. Extension is added automatically.
name = "Nidhogg_Warrior"
hp = 99
atk = 1
def = 1
check = "The Nidhogg_Warrior is\rsearching for the Nidhogg"
dialogbubble = "rightlarge" -- See documentation for what bubbles you have available.
canspare = false
cancheck = true
GreetCounter = 5
Berserk = false
encounter:
-- A basic encounter script skeleton you can copy and modify for your own creations.
encountertext = "Nidhogg_Warrior is\rrunning frantically"
nextwaves = {"bullettest_chaserorb"}
wavetimer = 5.0
arenasize = {155, 130}
music = "musAncientGuardian"
enemies = {"poseur"}
require("Monsters.poseur")
enemypositions = {{0, 0}}
-- A custom list with attacks to choose from.
-- Actual selection happens in EnemyDialogueEnding().
-- Put here in case you want to use it.
possible_attacks = {"bullettest_bouncy", "bullettest_chaserorb", "bullettest_touhou"}
function EncounterStarting()
-- If you want to change the game state immediately, this is the place.
Player.lv = 20
Player.hp = 99
Player.name = "Teemies"
poseur.GetVar("Berserk")
end
Thank you for reading.
The answer to my problem was to use SetGobal(), GetGobal().
For some reasons my previous attempt to simply use SetGobal()Resulted in nil value despite writing it like that SetGobal("Berserk",true) gave me a nill value error, as soon as I launch the game.
But I still used them wrong. First I needed to put it SetGobal() at the end of the condition instead of at the start of the the poseur.lua script because the change of value... for some reasons was being overwritten by it first installment.
And to test the variable in the function in my encounter.lua, I needed to write it like that
function EnemyDialogueStarting()
-- Good location for setting monster dialogue depending on how the battle is going.
if GetGlobal("Jimmies") == true then
TEEEST()
end
end
Also any tips an suggestions are still welcome !
Well firstly, in lua simple values like bool and number are copied on assignment:
global={}
a=2
global.a=a--this is a copy
a=4--this change won't affect value in table
print(global.a)--2
print(a)--4
Secondly,
SetGobal and the other mentioned functions are not part of lua language, they must be related to your engine. Probably, they use word 'Global' not as lua 'global' but in a sense defined by engine.
Depending on the engine specifics these functions might as well do a deep copy of any variable they're given (or might as well not work with complicated objects).
I have a WoW/LUA script that I am attempting to start, but it seems to conflict with the Stubby addon, which is a part of the Auctioneer addon, I believe. Here is the message I receive:
Error occured in: Stubby Count: 1 Message: Error: Original call failed
after running hooks for: ChatFrame_OnEvent Usage:
SendChatMessage(text [,type] [,language] [,targetPlayer]) Debug:
(tail call): ? [string ":OnEvent"]:1:
[string ":OnEvent"]:1
Now, the only thing that's happening in the conflicting addon is:
ChatFrame_AddMessageEventFilter("CHAT_MSG_PARTY", partyMsg)
The code within partyMsg is very simple as well:
local function partyMsg(msg,author,language,lineID,senderGUID)
if (store ~= msg) then
SendChatMessage(msg,"SAY",nil,nil);
end
store = msg;
end
Is this error due to two addons both trying to filter the chat frame? If so, how can this be done? It seems odd to me that Blizzard would have such a simple and yet important concept limited to one addon.
I think I see what happened here.
The reference you were using, Events/Communication, shows only the specific parameters for a particular event, regardless of context.
The context is usually an OnEvent handler.
The ChatFrame_AddMessageEventFilter function lets you use the chat frame's OnEvent handler instead of your own for chat frame events, and has well defined parameters for filters you add.
An OnEvent handler might look like:
function Foo_OnEvent(self, event, ...)
A 'ChatFrame' filter must look like this, for the first two parameters:
function Foo_ChatFrameFilter(self, event, msg, ...)
The ChatFrame filter is specific. For OnEvent however, you can make a Lua 'handler' that doesnt care about what frame it came from:
<OnEvent>
MyEventHandler(event, ...)
</OnEvent>
For the sake of completion, I will include the entire source of this addon:
local function partyMsg(someTable,msgType,msg,user,language,...)
if (store ~= msg) then
SendChatMessage(user .. " just said: ".. msg .. " using that sneaky " .. language .. " language.");
end
store = msg;
return false;
end
ChatFrame_AddMessageEventFilter("CHAT_MSG_PARTY", partyMsg)
ChatFrame_AddMessageEventFilter("CHAT_MSG_PARTY_LEADER",partyMsg)
There were a couple issues with the original code:
1) I was using WoWWiki to get my information, and first, I read it incorrectly. lineID and senderGUID are not the 4th and 5th arguments. Then, beyond this, WoWWiki is incorrect on this page in general. The correct arguments are listed above in the source. The first argument, a table, I am unsure of its purpose. In any case, this code now works fully.