diff --git a/lib/python/gladevcp/combi_dro.py b/lib/python/gladevcp/combi_dro.py index 8a5592aceab..e77cea6c42f 100644 --- a/lib/python/gladevcp/combi_dro.py +++ b/lib/python/gladevcp/combi_dro.py @@ -495,9 +495,12 @@ def _position(self, object, p, rel_p, dtg, joint_actual_position): main_dro = tmpl(main * scale) left_dro = tmpl(left * scale) right_dro = tmpl(right * scale) - self.widgets["main_dro"].set_label(main_dro) - self.widgets["dro_left"].set_label(left_dro) - self.widgets["dro_right"].set_label(right_dro) + # GTK relayouts the whole window on every set_label(), even for the + # same text, so only touch the labels whose text changed + for name, text in (("main_dro", main_dro), ("dro_left", left_dro), ("dro_right", right_dro)): + label = self.widgets[name] + if label.get_label() != text: + label.set_label(text) self.dtg = dtg * scale self.abs_pos = abs_pos * scale self.rel_pos = rel_pos * scale diff --git a/src/emc/usr_intf/gmoccapy/dialogs.py b/src/emc/usr_intf/gmoccapy/dialogs.py index 842df6b2a08..2d00309f4f5 100644 --- a/src/emc/usr_intf/gmoccapy/dialogs.py +++ b/src/emc/usr_intf/gmoccapy/dialogs.py @@ -125,18 +125,25 @@ def warning_dialog(self, caller, message, secondary = None, title = _("Operator self.emit("play_sound", "alert") dialog.set_title(title) + timer = None def periodic(): + nonlocal timer if caller.halcomp[confirm_pin]: + timer = None dialog.response(Gtk.ResponseType.OK) return False if active_pin is not None: if not caller.halcomp[active_pin]: + timer = None dialog.response(Gtk.ResponseType.CANCEL) return False return True - GLib.timeout_add(100, periodic) + timer = GLib.timeout_add(100, periodic) response = dialog.run() + # closed with the button: stop watching the pins + if timer is not None: + GLib.source_remove(timer) dialog.destroy() return response == Gtk.ResponseType.OK diff --git a/src/emc/usr_intf/gmoccapy/gmoccapy.py b/src/emc/usr_intf/gmoccapy/gmoccapy.py index cf17081c331..b31d5d3892b 100644 --- a/src/emc/usr_intf/gmoccapy/gmoccapy.py +++ b/src/emc/usr_intf/gmoccapy/gmoccapy.py @@ -167,6 +167,15 @@ def excepthook(exc_type, exc_obj, exc_tb): AXISLIST = ['offset', 'X', 'Y', 'Z', 'A', 'B', 'C', 'U', 'V', 'W', 'Rot', 'name'] +def set_label(label, text): + """Set a label's text only if it changed. + + GTK relayouts the whole window on every set_label(), even for the same + text, which costs a lot of CPU when done every cycle. + """ + if label.get_label() != text: + label.set_label(text) + class gmoccapy(object): def __init__(self, argv): @@ -552,7 +561,8 @@ def __init__(self, argv): # CYCLE_TIME = time, in milliseconds, that display will sleep between polls cycle_time = self.get_ini_info.get_cycle_time() GLib.timeout_add( cycle_time, self._periodic ) # time between calls to the function, in milliseconds - GLib.timeout_add(1000, self._periodic_1s) # 1 s timer for elapsed time display + GLib.timeout_add(1000, self._periodic_1s) # 1 s timer for elapsed time and clock display + self._update_clock() self.elapsed_time_run = 0 self.progress = 0 @@ -2815,19 +2825,21 @@ def _periodic(self): self._update_halui_pin() self._update_vc() - self.widgets.lbl_time.set_label(strftime("%H:%M:%S") + "\n" + strftime("%d.%m.%Y")) - # keep the timer running return True # every 1 second this gets called def _periodic_1s(self): + self._update_clock() if self.GSTAT.is_auto_running() and not self.GSTAT.is_auto_paused(): self.elapsed_time_run += 1 self._update_progress() return True + def _update_clock(self): + self.widgets.lbl_time.set_label(strftime("%H:%M:%S") + "\n" + strftime("%d.%m.%Y")) + def _show_error(self, error): kind, text = error if kind in (linuxcnc.NML_ERROR, linuxcnc.OPERATOR_ERROR): @@ -3937,7 +3949,7 @@ def _update_vel(self): # self.stat.program_units will return 1 for inch, 2 for mm and 3 for cm real_feed = float(self.stat.settings[1] * self.stat.feedrate) if self.stat.program_units != 1: - self.widgets.lbl_current_vel.set_text("{0:d}".format(int(self.stat.current_vel * 60.0 * self.faktor))) + set_label(self.widgets.lbl_current_vel, "{0:d}".format(int(self.stat.current_vel * 60.0 * self.faktor))) if "G95" in self.active_gcodes: feed_str = "{0:d}".format(int(self.stat.settings[1])) real_feed_str = "F {0:.2f}".format(real_feed) @@ -3945,7 +3957,7 @@ def _update_vel(self): feed_str = "{0:d}".format(int(self.stat.settings[1])) real_feed_str = "F {0:d}".format(int(real_feed)) else: - self.widgets.lbl_current_vel.set_text("{0:.2f}".format(self.stat.current_vel * 60.0 * self.faktor)) + set_label(self.widgets.lbl_current_vel, "{0:.2f}".format(self.stat.current_vel * 60.0 * self.faktor)) if "G95" in self.active_gcodes: feed_str = "{0:.4f}".format(self.stat.settings[1]) real_feed_str = "F {0:.4f}".format(real_feed) @@ -3958,8 +3970,8 @@ def _update_vel(self): if not real_feed: real_feed_str = "F 0" - self.widgets.lbl_active_feed.set_label(feed_str) - self.widgets.lbl_feed_act.set_text(real_feed_str) + set_label(self.widgets.lbl_active_feed, feed_str) + set_label(self.widgets.lbl_feed_act, real_feed_str) def _update_coolant(self): if self.stat.flood: @@ -4506,18 +4518,18 @@ def _update_spindle(self): return # set the S label in active code frame - self.widgets.active_speed_label.set_label("{0:.0f}".format(self.stat.settings[2])) + set_label(self.widgets.active_speed_label, "{0:.0f}".format(self.stat.settings[2])) # set the 'Spindle [rpm]' label #Note: self.stat.spindle[0]['speed'] does not reflect 'spindle.0.speed-out' pins when using G96 mode (issue #3449) speed = hal.get_value("spindle.0.speed-out") # catch very large values eg when using G96 w/o D value if speed > self.max_spindle_disp: - self.widgets.lbl_spindle_act.set_text(">"+str(self.max_spindle_disp)) + set_label(self.widgets.lbl_spindle_act, ">"+str(self.max_spindle_disp)) elif speed < -self.max_spindle_disp: - self.widgets.lbl_spindle_act.set_text("<"+str(self.max_spindle_disp)) + set_label(self.widgets.lbl_spindle_act, "<"+str(self.max_spindle_disp)) else: - self.widgets.lbl_spindle_act.set_text("{0}".format(int(round(speed)))) + set_label(self.widgets.lbl_spindle_act, "{0}".format(int(round(speed)))) def _update_vc(self): #Note: self.stat.spindle[0]['speed'] does not reflect 'spindle.0.speed-out' pins when using G96 mode (issue #3449) @@ -4537,7 +4549,7 @@ def _update_vc(self): text = "Vc= {0:2.1f}".format(vc) else: text = "Vc= {0:.2f}".format(vc) - self.widgets.lbl_vc.set_text(text) + set_label(self.widgets.lbl_vc, text) def on_program_time(self, widget, estimate): """The parse's time estimate for the program just loaded. @@ -4648,13 +4660,13 @@ def _set_spindle(self, command): rpm_out = rpm / self.stat.spindle[0]['override'] except: rpm_out = 0 - self.widgets.lbl_spindle_act.set_label("{0}".format(int(rpm))) + set_label(self.widgets.lbl_spindle_act, "{0}".format(int(rpm))) if command == "stop": # documentation of self.command.spindle() # linuxcnc.spindle(direction, speed, spindle=0) self.command.spindle(0) - self.widgets.lbl_spindle_act.set_label("0") + set_label(self.widgets.lbl_spindle_act, "0") elif command == "forward": self.command.spindle(1, rpm_out) elif command == "reverse": diff --git a/src/emc/usr_intf/gremlin/gremlin.py b/src/emc/usr_intf/gremlin/gremlin.py index 84d31c7b5d7..4bb214d0545 100755 --- a/src/emc/usr_intf/gremlin/gremlin.py +++ b/src/emc/usr_intf/gremlin/gremlin.py @@ -133,6 +133,7 @@ def C(s): self.connect('resize', self.reshape) # 'map', not 'map-event': a GLArea has no window of its own to get one. self.connect('map', self.map) + self.connect('unmap', self.unmap) self.connect('render', self.render) self.connect('motion-notify-event', self.motion) self.connect('button-press-event', self.pressed) @@ -151,6 +152,7 @@ def C(s): self.fingerprint = () + self.poll_timer = None self.lat = 0 self.minlat = -90 @@ -293,15 +295,25 @@ def _redraw(self): def clear_live_plotter(self): self.logger.clear() + # 'map' fires every time the widget is shown again, eg when gmoccapy + # leaves its settings page, so only start the poll if it is not running. def map(self, *args): - GLib.timeout_add(50, self.poll) + if self.poll_timer is None: + self.poll_timer = GLib.timeout_add(50, self.poll) + + # Nothing to draw while hidden, so stop polling. + def unmap(self, *args): + if self.poll_timer is not None: + GLib.source_remove(self.poll_timer) + self.poll_timer = None def poll(self): s = self.stat try: s.poll() except: - return + self.poll_timer = None + return False fingerprint = (self.logger.npts, self.soft_limits(), s.actual_position, s.joint_actual_position, s.homed, s.g5x_offset, s.g92_offset, s.limit, s.tool_in_spindle, @@ -311,7 +323,6 @@ def poll(self): self.fingerprint = fingerprint self.queue_render() - # return self.visible return True @rs274.glcanon.with_context