diff options
author | Gary Bressler <garybressler@nc.rr.com> | 2010-04-30 14:04:11 -0400 |
---|---|---|
committer | Gary Bressler <garybressler@nc.rr.com> | 2010-04-30 14:04:11 -0400 |
commit | c21dea9f97dd31ad8a915469edc01f44345a469e (patch) | |
tree | 9a66ff34dc8c90c695572038b443bc2fd05e8cbf /unit_trace/viz/viewer.py | |
parent | 6cfc2cc3bb104ef81e4d9e70f63ab803949f9764 (diff) |
Fixes related to scrolling, along with the display of some extra information. Updated documentation.
Diffstat (limited to 'unit_trace/viz/viewer.py')
-rw-r--r-- | unit_trace/viz/viewer.py | 246 |
1 files changed, 155 insertions, 91 deletions
diff --git a/unit_trace/viz/viewer.py b/unit_trace/viz/viewer.py index 4f7a511..bb1385c 100644 --- a/unit_trace/viz/viewer.py +++ b/unit_trace/viz/viewer.py | |||
@@ -30,7 +30,7 @@ class GraphContextMenu(gtk.Menu): | |||
30 | else: | 30 | else: |
31 | for layer in selected: | 31 | for layer in selected: |
32 | for event in selected[layer]: | 32 | for event in selected[layer]: |
33 | string = str(event) | 33 | string = event.str_short(info_win.get_unit()) |
34 | if len(string) > GraphContextMenu.MAX_STR_LEN - 3: | 34 | if len(string) > GraphContextMenu.MAX_STR_LEN - 3: |
35 | string = string[:GraphContextMenu.MAX_STR_LEN - 3] + '...' | 35 | string = string[:GraphContextMenu.MAX_STR_LEN - 3] + '...' |
36 | item = gtk.MenuItem(string) | 36 | item = gtk.MenuItem(string) |
@@ -68,19 +68,23 @@ class GraphArea(gtk.DrawingArea): | |||
68 | self.set_set_scroll_adjustments_signal('set-scroll-adjustments') | 68 | self.set_set_scroll_adjustments_signal('set-scroll-adjustments') |
69 | 69 | ||
70 | self.add_events(gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.POINTER_MOTION_MASK | gtk.gdk.POINTER_MOTION_HINT_MASK | | 70 | self.add_events(gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.POINTER_MOTION_MASK | gtk.gdk.POINTER_MOTION_HINT_MASK | |
71 | gtk.gdk.BUTTON_RELEASE_MASK | gtk.gdk.EXPOSURE_MASK) | 71 | gtk.gdk.BUTTON_RELEASE_MASK | gtk.gdk.EXPOSURE_MASK | gtk.gdk.LEAVE_NOTIFY_MASK) |
72 | 72 | ||
73 | self.band_rect = None | 73 | self.band_rect = None |
74 | self.ctrl_clicked = False | 74 | self.ctrl_clicked = False |
75 | self.cursor_pos = None | ||
75 | self.last_selected = {} | 76 | self.last_selected = {} |
76 | self.dirtied_regions = [] | 77 | self.dirtied_regions = [] |
77 | 78 | ||
79 | self.get_graph().update_view(self.cur_x, self.cur_y, self.width, self.height, self.scale) | ||
80 | |||
78 | self.connect('expose-event', self.expose) | 81 | self.connect('expose-event', self.expose) |
79 | self.connect('size-allocate', self.size_allocate) | 82 | self.connect('size-allocate', self.size_allocate) |
80 | self.connect('set-scroll-adjustments', self.set_scroll_adjustments) | 83 | self.connect('set-scroll-adjustments', self.set_scroll_adjustments) |
81 | self.connect('button-press-event', self.button_press) | 84 | self.connect('button-press-event', self.button_press) |
82 | self.connect('button-release-event', self.button_release) | 85 | self.connect('button-release-event', self.button_release) |
83 | self.connect('motion-notify-event', self.motion_notify) | 86 | self.connect('motion-notify-event', self.motion_notify) |
87 | self.connect('leave-notify-event', self.leave_notify) | ||
84 | 88 | ||
85 | def output_to_file(self, filename, ftype): | 89 | def output_to_file(self, filename, ftype): |
86 | """Outputs the entire graph to a file.""" | 90 | """Outputs the entire graph to a file.""" |
@@ -92,17 +96,17 @@ class GraphArea(gtk.DrawingArea): | |||
92 | surface = SVGSurface() | 96 | surface = SVGSurface() |
93 | else: | 97 | else: |
94 | raise ValueError | 98 | raise ValueError |
95 | 99 | ||
96 | surface.renew(graph.get_width(), graph.get_height()) | 100 | surface.renew(graph.get_width(), graph.get_height()) |
97 | graph.set_tmp_surface(surface) | 101 | graph.set_tmp_surface(surface) |
98 | graph.render_all(self.renderer.get_schedule()) | 102 | graph.render_all(self.renderer.get_schedule()) |
99 | surface.write_out(filename) | 103 | surface.write_out(filename) |
100 | graph.revert_surface() | 104 | graph.revert_surface() |
101 | 105 | ||
102 | def expose(self, widget, expose_event, data=None): | 106 | def expose(self, widget, expose_event, data=None): |
103 | ctx = widget.window.cairo_create() | 107 | ctx = widget.window.cairo_create() |
104 | graph = self.renderer.get_graph() | 108 | graph = self.get_graph() |
105 | graph.update_view(self.cur_x, self.cur_y, self.width, self.height, self.scale, ctx) | 109 | graph.load_ctx(ctx) |
106 | 110 | ||
107 | # If X caused the expose event, we need to update the entire area, not just the | 111 | # If X caused the expose event, we need to update the entire area, not just the |
108 | # changes we might have made. An expose event caused by X needs to take priority | 112 | # changes we might have made. An expose event caused by X needs to take priority |
@@ -113,11 +117,13 @@ class GraphArea(gtk.DrawingArea): | |||
113 | self.dirtied_regions = [(expose_event.area.x, expose_event.area.y, | 117 | self.dirtied_regions = [(expose_event.area.x, expose_event.area.y, |
114 | expose_event.area.width, expose_event.area.height)] | 118 | expose_event.area.width, expose_event.area.height)] |
115 | 119 | ||
116 | graph.render_surface(self.renderer.get_schedule(), self.dirtied_regions) | 120 | virt_dirtied_regions = graph.real_to_virt_list(self.dirtied_regions) |
121 | graph.render_surface(self.renderer.get_schedule(), virt_dirtied_regions) | ||
117 | 122 | ||
118 | # render dragging band rectangle, if there is one | 123 | # render dragging band rectangle, if there is one |
119 | if self.band_rect is not None: | 124 | if self.band_rect is not None: |
120 | x, y, width, height = self.band_rect | 125 | x, y, width, height = graph.virt_to_real(self.band_rect[0], self.band_rect[1], |
126 | self.band_rect[2], self.band_rect[3]) | ||
121 | thickness = GraphFormat.BAND_THICKNESS | 127 | thickness = GraphFormat.BAND_THICKNESS |
122 | color = GraphFormat.BAND_COLOR | 128 | color = GraphFormat.BAND_COLOR |
123 | 129 | ||
@@ -136,21 +142,23 @@ class GraphArea(gtk.DrawingArea): | |||
136 | 142 | ||
137 | def get_schedule(self): | 143 | def get_schedule(self): |
138 | return self.renderer.get_schedule() | 144 | return self.renderer.get_schedule() |
139 | 145 | ||
140 | def zoom_in(self): | 146 | def zoom_in(self): |
141 | scale = self.scale + GraphArea.ZOOM_INCR | 147 | scale = self.scale + GraphArea.ZOOM_INCR |
142 | if scale > GraphArea.MAX_ZOOM_IN: | 148 | if scale > GraphArea.MAX_ZOOM_IN: |
143 | scale = GraphArea.MAX_ZOOM_IN | 149 | scale = GraphArea.MAX_ZOOM_IN |
144 | self.set_scale(scale) | 150 | self.set_scale(scale) |
145 | self.config_scrollbars(self.cur_x, self.cur_y, self.scale) | 151 | self.config_scrollbars(self.cur_x, self.cur_y, self.scale) |
146 | 152 | self._pos_update() | |
153 | |||
147 | def zoom_out(self): | 154 | def zoom_out(self): |
148 | scale = self.scale - GraphArea.ZOOM_INCR | 155 | scale = self.scale - GraphArea.ZOOM_INCR |
149 | if scale < GraphArea.MIN_ZOOM_OUT: | 156 | if scale < GraphArea.MIN_ZOOM_OUT: |
150 | scale = GraphArea.MIN_ZOOM_OUT | 157 | scale = GraphArea.MIN_ZOOM_OUT |
151 | self.set_scale(scale) | 158 | self.set_scale(scale) |
152 | self.config_scrollbars(self.cur_x, self.cur_y, self.scale) | 159 | self.config_scrollbars(self.cur_x, self.cur_y, self.scale) |
153 | 160 | self._pos_update() | |
161 | |||
154 | def set_scale(self, scale): | 162 | def set_scale(self, scale): |
155 | if scale == self.scale: | 163 | if scale == self.scale: |
156 | return | 164 | return |
@@ -165,7 +173,7 @@ class GraphArea(gtk.DrawingArea): | |||
165 | value = max(value, self.horizontal.get_lower()) | 173 | value = max(value, self.horizontal.get_lower()) |
166 | value = min(value, self.horizontal.get_upper() - self.horizontal.get_page_size()) | 174 | value = min(value, self.horizontal.get_upper() - self.horizontal.get_page_size()) |
167 | self.horizontal.set_value(value) | 175 | self.horizontal.set_value(value) |
168 | 176 | ||
169 | def set_vvalue(self, value): | 177 | def set_vvalue(self, value): |
170 | if self.vertical is None: | 178 | if self.vertical is None: |
171 | return | 179 | return |
@@ -173,7 +181,7 @@ class GraphArea(gtk.DrawingArea): | |||
173 | value = max(value, self.vertical.get_lower()) | 181 | value = max(value, self.vertical.get_lower()) |
174 | value = min(value, self.vertical.get_upper() - self.vertical.get_page_size()) | 182 | value = min(value, self.vertical.get_upper() - self.vertical.get_page_size()) |
175 | self.vertical.set_value(value) | 183 | self.vertical.set_value(value) |
176 | 184 | ||
177 | def set_scroll_adjustments(self, widget, horizontal, vertical, data=None): | 185 | def set_scroll_adjustments(self, widget, horizontal, vertical, data=None): |
178 | graph = self.renderer.get_graph() | 186 | graph = self.renderer.get_graph() |
179 | width = graph.get_width() | 187 | width = graph.get_width() |
@@ -192,20 +200,27 @@ class GraphArea(gtk.DrawingArea): | |||
192 | self.cur_x = min(adjustment.value, self.renderer.get_graph().get_width()) | 200 | self.cur_x = min(adjustment.value, self.renderer.get_graph().get_width()) |
193 | self.cur_x = max(adjustment.value, 0.0) | 201 | self.cur_x = max(adjustment.value, 0.0) |
194 | 202 | ||
195 | self.renderer.get_graph().render_surface(self.renderer.get_schedule(), [(0, 0, self.width, self.height)], True) | 203 | self.get_graph().render_surface(self.renderer.get_schedule(), |
204 | [self.get_graph().real_to_virt(0, 0, self.width, self.height)], True) | ||
196 | self._dirty(0, 0, self.width, self.height) | 205 | self._dirty(0, 0, self.width, self.height) |
197 | 206 | ||
207 | self._pos_update() | ||
208 | |||
198 | def vertical_value_changed(self, adjustment): | 209 | def vertical_value_changed(self, adjustment): |
199 | self.cur_y = min(adjustment.value, self.renderer.get_graph().get_height()) | 210 | self.cur_y = min(adjustment.value, self.renderer.get_graph().get_height()) |
200 | self.cur_y = max(adjustment.value, 0.0) | 211 | self.cur_y = max(adjustment.value, 0.0) |
201 | 212 | ||
202 | self.renderer.get_graph().render_surface(self.renderer.get_schedule(), [(0, 0, self.width, self.height)], True) | 213 | self.get_graph().render_surface(self.renderer.get_schedule(), |
214 | [self.get_graph().real_to_virt(0, 0, self.width, self.height)], True) | ||
203 | self._dirty(0, 0, self.width, self.height) | 215 | self._dirty(0, 0, self.width, self.height) |
204 | 216 | ||
217 | self._pos_update() | ||
218 | |||
205 | def size_allocate(self, widget, allocation): | 219 | def size_allocate(self, widget, allocation): |
206 | self.width = allocation.width | 220 | self.width = allocation.width |
207 | self.height = allocation.height | 221 | self.height = allocation.height |
208 | self.config_scrollbars(self.cur_x, self.cur_y, self.scale) | 222 | self.config_scrollbars(self.cur_x, self.cur_y, self.scale) |
223 | self._pos_update() | ||
209 | 224 | ||
210 | def config_scrollbars(self, hvalue, vvalue, scale): | 225 | def config_scrollbars(self, hvalue, vvalue, scale): |
211 | graph = self.renderer.get_graph() | 226 | graph = self.renderer.get_graph() |
@@ -224,11 +239,11 @@ class GraphArea(gtk.DrawingArea): | |||
224 | graph.get_attrs().y_item_size * GraphArea.VERT_PAGE_SCROLL_FACTOR / scale, | 239 | graph.get_attrs().y_item_size * GraphArea.VERT_PAGE_SCROLL_FACTOR / scale, |
225 | self.height / scale) | 240 | self.height / scale) |
226 | self.set_vvalue(vvalue) | 241 | self.set_vvalue(vvalue) |
227 | 242 | ||
228 | def refresh_all(self): | 243 | def refresh_all(self): |
229 | """Refreshes the entire visible screen.""" | 244 | """Refreshes the entire visible screen.""" |
230 | self._dirty(0, 0, self.width, self.height) | 245 | self._dirty(0, 0, self.width, self.height) |
231 | 246 | ||
232 | def refresh_events(self, sender, new, old, replace): | 247 | def refresh_events(self, sender, new, old, replace): |
233 | """Even if the selected areas change on one graph, they change | 248 | """Even if the selected areas change on one graph, they change |
234 | everywhere, and different events might be in different regions on | 249 | everywhere, and different events might be in different regions on |
@@ -240,7 +255,7 @@ class GraphArea(gtk.DrawingArea): | |||
240 | refreshes the drawing of the graph that requested the change.""" | 255 | refreshes the drawing of the graph that requested the change.""" |
241 | if self is not sender: | 256 | if self is not sender: |
242 | self.renderer.get_graph().render_events(new, True) | 257 | self.renderer.get_graph().render_events(new, True) |
243 | 258 | ||
244 | self._tag_events(new) | 259 | self._tag_events(new) |
245 | 260 | ||
246 | if self is sender: | 261 | if self is sender: |
@@ -252,7 +267,7 @@ class GraphArea(gtk.DrawingArea): | |||
252 | else: | 267 | else: |
253 | self.renderer.get_schedule().remove_selected(old) | 268 | self.renderer.get_schedule().remove_selected(old) |
254 | self.renderer.get_schedule().add_selected(new) | 269 | self.renderer.get_schedule().add_selected(new) |
255 | 270 | ||
256 | self.emit('update-sel-changes', self.renderer.get_schedule().get_selected()) | 271 | self.emit('update-sel-changes', self.renderer.get_schedule().get_selected()) |
257 | 272 | ||
258 | def _find_max_layer(self, regions): | 273 | def _find_max_layer(self, regions): |
@@ -267,11 +282,9 @@ class GraphArea(gtk.DrawingArea): | |||
267 | for layer in events: | 282 | for layer in events: |
268 | for event in events[layer]: | 283 | for event in events[layer]: |
269 | if not events[layer][event][self].is_dummy(): | 284 | if not events[layer][event][self].is_dummy(): |
270 | x, y, width, height = events[layer][event][self].get_dimensions() | 285 | dim = events[layer][event][self].get_dimensions() |
271 | self._dirty_inflate((x - self.cur_x) * self.scale, | 286 | x, y, width, height = self.get_graph().virt_to_real(dim[0], dim[1], dim[2], dim[3]) |
272 | (y - self.cur_y) * self.scale, | 287 | self._dirty_inflate(x, y, width, height, |
273 | width * self.scale, | ||
274 | height * self.scale, | ||
275 | GraphFormat.BORDER_THICKNESS * self.scale) | 288 | GraphFormat.BORDER_THICKNESS * self.scale) |
276 | 289 | ||
277 | def _tag_events(self, selected): | 290 | def _tag_events(self, selected): |
@@ -303,15 +316,27 @@ class GraphArea(gtk.DrawingArea): | |||
303 | if event not in coll[event.get_layer()]: | 316 | if event not in coll[event.get_layer()]: |
304 | coll[event.get_layer()][event] = {} | 317 | coll[event.get_layer()][event] = {} |
305 | 318 | ||
319 | def leave_notify(self, widget, leave_event): | ||
320 | self.cursor_pos = None | ||
321 | self.emit('update-event-description', None) | ||
322 | |||
306 | def motion_notify(self, widget, motion_event, data=None): | 323 | def motion_notify(self, widget, motion_event, data=None): |
307 | msg = None | 324 | self.cursor_pos = (motion_event.x, motion_event.y) |
325 | self._pos_update() | ||
326 | |||
327 | def _pos_update(self): | ||
328 | self.get_graph().update_view(self.cur_x, self.cur_y, self.width, self.height, self.scale) | ||
329 | |||
330 | if self.cursor_pos is None: | ||
331 | return | ||
308 | 332 | ||
309 | graph = self.renderer.get_graph() | 333 | graph = self.renderer.get_graph() |
310 | 334 | ||
311 | graph.render_surface(self.renderer.get_schedule(), [(motion_event.x, motion_event.y, | 335 | graph.render_surface(self.renderer.get_schedule(), |
312 | 0, 0)], True) | 336 | [graph.real_to_virt(self.cursor_pos[0], self.cursor_pos[1], 0, 0)], True) |
313 | 337 | ||
314 | just_selected = graph.get_intersecting_regions(motion_event.x, motion_event.y, 0, 0) | 338 | cur_x_v, cur_y_v, w, h = graph.real_to_virt(self.cursor_pos[0], self.cursor_pos[1], 0, 0) |
339 | just_selected = graph.get_intersecting_regions(cur_x_v, cur_y_v, 0, 0) | ||
315 | was_selected = self.renderer.get_schedule().get_selected() | 340 | was_selected = self.renderer.get_schedule().get_selected() |
316 | if not just_selected: | 341 | if not just_selected: |
317 | msg = '' | 342 | msg = '' |
@@ -323,10 +348,11 @@ class GraphArea(gtk.DrawingArea): | |||
323 | the_event = event | 348 | the_event = event |
324 | break | 349 | break |
325 | 350 | ||
326 | msg = str(the_event) | 351 | msg = the_event.str_short(graph.get_attrs().unit) |
327 | 352 | ||
328 | self.emit('update-event-description', the_event, msg) | 353 | self.emit('update-event-description', the_event) |
329 | 354 | ||
355 | virt_x, virt_y, w, h = graph.real_to_virt(self.cursor_pos[0], self.cursor_pos[1], 0, 0) | ||
330 | if self.band_rect is not None: | 356 | if self.band_rect is not None: |
331 | remove_selected = {} | 357 | remove_selected = {} |
332 | add_selected = {} | 358 | add_selected = {} |
@@ -334,14 +360,12 @@ class GraphArea(gtk.DrawingArea): | |||
334 | # dragging a rectangle | 360 | # dragging a rectangle |
335 | x = self.band_rect[0] | 361 | x = self.band_rect[0] |
336 | y = self.band_rect[1] | 362 | y = self.band_rect[1] |
337 | width = motion_event.x - self.band_rect[0] | 363 | width = virt_x - self.band_rect[0] |
338 | height = motion_event.y - self.band_rect[1] | 364 | height = virt_y - self.band_rect[1] |
339 | old_x, old_y, old_width, old_height = self.band_rect | 365 | old_x, old_y, old_width, old_height = self.band_rect |
340 | 366 | ||
341 | x_p, y_p, width_p, height_p = self._positivify(x, y, width, height) | 367 | x_p, y_p, width_p, height_p = self._positivify_int(x, y, width, height) |
342 | old_x_p, old_y_p, old_width_p, old_height_p = self._positivify(old_x, old_y, old_width, old_height) | 368 | old_x_p, old_y_p, old_width_p, old_height_p = self._positivify_int(old_x, old_y, old_width, old_height) |
343 | x_p, y_p, width_p, height_p = int(x_p), int(y_p), int(width_p), int(height_p) | ||
344 | old_x_p, old_y_p, old_width_p, old_height_p = int(old_x_p), int(old_y_p), int(old_width_p), int(old_height_p) | ||
345 | 369 | ||
346 | new_reg = gtk.gdk.region_rectangle(gtk.gdk.Rectangle(x_p, y_p, width_p, height_p)) | 370 | new_reg = gtk.gdk.region_rectangle(gtk.gdk.Rectangle(x_p, y_p, width_p, height_p)) |
347 | old_reg = gtk.gdk.region_rectangle(gtk.gdk.Rectangle(old_x_p, old_y_p, old_width_p, old_height_p)) | 371 | old_reg = gtk.gdk.region_rectangle(gtk.gdk.Rectangle(old_x_p, old_y_p, old_width_p, old_height_p)) |
@@ -354,7 +378,7 @@ class GraphArea(gtk.DrawingArea): | |||
354 | dirty_list = [] | 378 | dirty_list = [] |
355 | for rect in remove_reg.get_rectangles(): | 379 | for rect in remove_reg.get_rectangles(): |
356 | dirty_list.append((rect.x, rect.y, rect.width, rect.height)) | 380 | dirty_list.append((rect.x, rect.y, rect.width, rect.height)) |
357 | graph.render_surface(self.renderer.get_schedule(), dirty_list, True) | 381 | graph.render_surface(self.renderer.get_schedule(), graph.real_to_virt_list(dirty_list), True) |
358 | for rect in dirty_list: | 382 | for rect in dirty_list: |
359 | rx, ry, rwidth, rheight = rect | 383 | rx, ry, rwidth, rheight = rect |
360 | i_regs = graph.get_intersecting_regions(rx, ry, rwidth, rheight) | 384 | i_regs = graph.get_intersecting_regions(rx, ry, rwidth, rheight) |
@@ -370,6 +394,7 @@ class GraphArea(gtk.DrawingArea): | |||
370 | for rect in add_reg.get_rectangles(): | 394 | for rect in add_reg.get_rectangles(): |
371 | dirty_list.append((rect.x, rect.y, rect.width, rect.height)) | 395 | dirty_list.append((rect.x, rect.y, rect.width, rect.height)) |
372 | graph.render_surface(self.renderer.get_schedule(), dirty_list, True) | 396 | graph.render_surface(self.renderer.get_schedule(), dirty_list, True) |
397 | |||
373 | for rect in dirty_list: | 398 | for rect in dirty_list: |
374 | rx, ry, rwidth, rheight = rect | 399 | rx, ry, rwidth, rheight = rect |
375 | i_regs = graph.get_intersecting_regions(rx, ry, rwidth, rheight) | 400 | i_regs = graph.get_intersecting_regions(rx, ry, rwidth, rheight) |
@@ -380,8 +405,10 @@ class GraphArea(gtk.DrawingArea): | |||
380 | self.band_rect = x, y, width, height | 405 | self.band_rect = x, y, width, height |
381 | self.emit('request-refresh-events', self, add_selected, remove_selected, False) | 406 | self.emit('request-refresh-events', self, add_selected, remove_selected, False) |
382 | 407 | ||
383 | self._dirty_rect_border(old_x, old_y, old_width, old_height, GraphFormat.BAND_THICKNESS) | 408 | x_r, y_r, width_r, height_r = graph.virt_to_real(x, y, width, height) |
384 | self._dirty_rect_border(x, y, width, height, GraphFormat.BAND_THICKNESS) | 409 | old_x_r, old_y_r, old_width_r, old_height_r = graph.virt_to_real(old_x, old_y, old_width, old_height) |
410 | self._dirty_rect_border(old_x_r, old_y_r, old_width_r, old_height_r, GraphFormat.BAND_THICKNESS * self.scale) | ||
411 | self._dirty_rect_border(x_r, y_r, width_r, height_r, GraphFormat.BAND_THICKNESS * self.scale) | ||
385 | 412 | ||
386 | def button_press(self, widget, button_event, data=None): | 413 | def button_press(self, widget, button_event, data=None): |
387 | graph = self.renderer.get_graph() | 414 | graph = self.renderer.get_graph() |
@@ -391,10 +418,11 @@ class GraphArea(gtk.DrawingArea): | |||
391 | if button_event.button == 1: | 418 | if button_event.button == 1: |
392 | self.left_button_start_coor = (button_event.x, button_event.y) | 419 | self.left_button_start_coor = (button_event.x, button_event.y) |
393 | graph.render_surface(self.renderer.get_schedule(), \ | 420 | graph.render_surface(self.renderer.get_schedule(), \ |
394 | [(button_event.x, button_event.y, 0, 0)], True) | 421 | [graph.real_to_virt(button_event.x, button_event.y, 0, 0)], True) |
395 | 422 | ||
396 | just_selected = graph.get_intersecting_regions(button_event.x, button_event.y, 0, 0) | 423 | b_x_r, b_y_r, w, h = graph.real_to_virt(button_event.x, button_event.y, 0, 0) |
397 | 424 | just_selected = graph.get_intersecting_regions(b_x_r, b_y_r, 0, 0) | |
425 | |||
398 | max_layer = self._find_max_layer(just_selected) | 426 | max_layer = self._find_max_layer(just_selected) |
399 | 427 | ||
400 | was_selected = self.renderer.get_schedule().get_selected() | 428 | was_selected = self.renderer.get_schedule().get_selected() |
@@ -418,7 +446,7 @@ class GraphArea(gtk.DrawingArea): | |||
418 | and event in was_selected[max_layer]): | 446 | and event in was_selected[max_layer]): |
419 | self._select_event(new_now_selected, event) | 447 | self._select_event(new_now_selected, event) |
420 | break # only pick one event when just clicking | 448 | break # only pick one event when just clicking |
421 | 449 | ||
422 | self.emit('request-refresh-events', self, new_now_selected, was_selected, True) | 450 | self.emit('request-refresh-events', self, new_now_selected, was_selected, True) |
423 | else: | 451 | else: |
424 | remove_selected = {} | 452 | remove_selected = {} |
@@ -435,7 +463,7 @@ class GraphArea(gtk.DrawingArea): | |||
435 | self.emit('request-refresh-events', self, add_selected, remove_selected, False) | 463 | self.emit('request-refresh-events', self, add_selected, remove_selected, False) |
436 | 464 | ||
437 | if self.band_rect is None: | 465 | if self.band_rect is None: |
438 | self.band_rect = (button_event.x, button_event.y, 0, 0) | 466 | self.band_rect = (b_x_r, b_y_r, 0, 0) |
439 | 467 | ||
440 | elif button_event.button == 3: | 468 | elif button_event.button == 3: |
441 | self._release_band() | 469 | self._release_band() |
@@ -456,7 +484,8 @@ class GraphArea(gtk.DrawingArea): | |||
456 | def _release_band(self): | 484 | def _release_band(self): |
457 | if self.band_rect is not None: | 485 | if self.band_rect is not None: |
458 | x, y, width, height = self.band_rect | 486 | x, y, width, height = self.band_rect |
459 | self._dirty_rect_border(x, y, width, height, GraphFormat.BAND_THICKNESS) | 487 | x_r, y_r, width_r, height_r = self.get_graph().virt_to_real(x, y, width, height) |
488 | self._dirty_rect_border(x_r, y_r, width_r, height_r, GraphFormat.BAND_THICKNESS * self.scale) | ||
460 | self.band_rect = None | 489 | self.band_rect = None |
461 | 490 | ||
462 | def _dirty(self, x, y, width, height): | 491 | def _dirty(self, x, y, width, height): |
@@ -498,6 +527,10 @@ class GraphArea(gtk.DrawingArea): | |||
498 | 527 | ||
499 | return x, y, width, height | 528 | return x, y, width, height |
500 | 529 | ||
530 | def _positivify_int(self, x, y, width, height): | ||
531 | p = self._positivify(x, y, width, height) | ||
532 | return (int(p[0]), int(p[1]), int(p[2]), int(p[3])) | ||
533 | |||
501 | class GraphWindow(gtk.ScrolledWindow): | 534 | class GraphWindow(gtk.ScrolledWindow): |
502 | def __init__(self, renderer): | 535 | def __init__(self, renderer): |
503 | super(GraphWindow, self).__init__(None, None) | 536 | super(GraphWindow, self).__init__(None, None) |
@@ -596,7 +629,7 @@ class MainWindow(gtk.Window): | |||
596 | 629 | ||
597 | def __init__(self): | 630 | def __init__(self): |
598 | super(MainWindow, self).__init__(gtk.WINDOW_TOPLEVEL) | 631 | super(MainWindow, self).__init__(gtk.WINDOW_TOPLEVEL) |
599 | 632 | ||
600 | self.add_events(gtk.gdk.BUTTON_PRESS_MASK) | 633 | self.add_events(gtk.gdk.BUTTON_PRESS_MASK) |
601 | 634 | ||
602 | self.connect('delete_event', self.delete_event) | 635 | self.connect('delete_event', self.delete_event) |
@@ -608,11 +641,11 @@ class MainWindow(gtk.Window): | |||
608 | 641 | ||
609 | agr = gtk.AccelGroup() | 642 | agr = gtk.AccelGroup() |
610 | self.add_accel_group(agr) | 643 | self.add_accel_group(agr) |
611 | 644 | ||
612 | # list of file items that are clickable if and only if at | 645 | # list of file items that are clickable if and only if at |
613 | # least one graph is viewable | 646 | # least one graph is viewable |
614 | self.sensitive_menu_items = [] | 647 | self.sensitive_menu_items = [] |
615 | 648 | ||
616 | save_item = gtk.ImageMenuItem('_Save Graph to File') | 649 | save_item = gtk.ImageMenuItem('_Save Graph to File') |
617 | img = gtk.Image() | 650 | img = gtk.Image() |
618 | img.set_from_stock(gtk.STOCK_SAVE_AS, gtk.ICON_SIZE_MENU) | 651 | img.set_from_stock(gtk.STOCK_SAVE_AS, gtk.ICON_SIZE_MENU) |
@@ -623,7 +656,7 @@ class MainWindow(gtk.Window): | |||
623 | save_item.connect('activate', self.save_item_activate) | 656 | save_item.connect('activate', self.save_item_activate) |
624 | save_item.set_sensitive(False) | 657 | save_item.set_sensitive(False) |
625 | self.sensitive_menu_items.append(save_item) | 658 | self.sensitive_menu_items.append(save_item) |
626 | 659 | ||
627 | quit_item = gtk.ImageMenuItem(gtk.STOCK_QUIT, agr) | 660 | quit_item = gtk.ImageMenuItem(gtk.STOCK_QUIT, agr) |
628 | key, mod = gtk.accelerator_parse('<Ctrl>Q') | 661 | key, mod = gtk.accelerator_parse('<Ctrl>Q') |
629 | quit_item.add_accelerator('activate', agr, key, mod, | 662 | quit_item.add_accelerator('activate', agr, key, mod, |
@@ -636,8 +669,8 @@ class MainWindow(gtk.Window): | |||
636 | file_item = gtk.MenuItem('_File', True) | 669 | file_item = gtk.MenuItem('_File', True) |
637 | file_item.set_submenu(file_menu) | 670 | file_item.set_submenu(file_menu) |
638 | 671 | ||
639 | move_item = gtk.ImageMenuItem('_Move to Time') | 672 | move_item = gtk.ImageMenuItem('_Jump to Time') |
640 | key, mod = gtk.accelerator_parse('<Ctrl>M') | 673 | key, mod = gtk.accelerator_parse('<Ctrl>J') |
641 | img = gtk.Image() | 674 | img = gtk.Image() |
642 | img.set_from_stock(gtk.STOCK_JUMP_TO, gtk.ICON_SIZE_MENU) | 675 | img.set_from_stock(gtk.STOCK_JUMP_TO, gtk.ICON_SIZE_MENU) |
643 | move_item.set_image(img) | 676 | move_item.set_image(img) |
@@ -645,7 +678,7 @@ class MainWindow(gtk.Window): | |||
645 | gtk.ACCEL_VISIBLE) | 678 | gtk.ACCEL_VISIBLE) |
646 | move_item.set_sensitive(False) | 679 | move_item.set_sensitive(False) |
647 | self.sensitive_menu_items.append(move_item) | 680 | self.sensitive_menu_items.append(move_item) |
648 | 681 | ||
649 | move_item.connect('activate', self.move_to_time_activate) | 682 | move_item.connect('activate', self.move_to_time_activate) |
650 | 683 | ||
651 | self.colors_item = gtk.ImageMenuItem('Co_lors') | 684 | self.colors_item = gtk.ImageMenuItem('Co_lors') |
@@ -656,14 +689,14 @@ class MainWindow(gtk.Window): | |||
656 | self.colors_item.add_accelerator('activate', agr, key, mod, | 689 | self.colors_item.add_accelerator('activate', agr, key, mod, |
657 | gtk.ACCEL_VISIBLE) | 690 | gtk.ACCEL_VISIBLE) |
658 | self.colors_item.set_sensitive(False) | 691 | self.colors_item.set_sensitive(False) |
659 | 692 | ||
660 | self.colors_item.connect('activate', self.colors_activate) | 693 | self.colors_item.connect('activate', self.colors_activate) |
661 | 694 | ||
662 | edit_menu.append(self.colors_item) | 695 | edit_menu.append(self.colors_item) |
663 | 696 | ||
664 | edit_item = gtk.MenuItem('_Edit', True) | 697 | edit_item = gtk.MenuItem('_Edit', True) |
665 | edit_item.set_submenu(edit_menu) | 698 | edit_item.set_submenu(edit_menu) |
666 | 699 | ||
667 | zoom_in_item = gtk.ImageMenuItem(gtk.STOCK_ZOOM_IN, agr) | 700 | zoom_in_item = gtk.ImageMenuItem(gtk.STOCK_ZOOM_IN, agr) |
668 | key, mod = gtk.accelerator_parse('<Ctrl>plus') | 701 | key, mod = gtk.accelerator_parse('<Ctrl>plus') |
669 | zoom_in_item.add_accelerator('activate', agr, key, mod, | 702 | zoom_in_item.add_accelerator('activate', agr, key, mod, |
@@ -701,20 +734,23 @@ class MainWindow(gtk.Window): | |||
701 | self.notebook.last_page = -1 | 734 | self.notebook.last_page = -1 |
702 | self.notebook.connect('switch-page', self.switch_page) | 735 | self.notebook.connect('switch-page', self.switch_page) |
703 | 736 | ||
704 | self.desc_label = gtk.Label('') | 737 | self.event_label = gtk.Label('') |
705 | self.desc_label.set_alignment(0.0, 0.0) | 738 | self.job_run_label = gtk.Label('') |
739 | self.job_rd_label = gtk.Label('') | ||
706 | 740 | ||
707 | self.vbox.pack_start(menu_bar, False, False, 0) | 741 | self.vbox.pack_start(menu_bar, False, False, 0) |
708 | self.vbox.pack_start(self.notebook, True, True, 0) | 742 | self.vbox.pack_start(self.notebook, True, True, 0) |
709 | self.vbox.pack_start(self.desc_label, False, False, 0) | 743 | self.vbox.pack_start(self.event_label, False, False, 0) |
710 | 744 | self.vbox.pack_start(self.job_run_label, False, False, 0) | |
745 | self.vbox.pack_start(self.job_rd_label, False, False, 0) | ||
711 | self.add(self.vbox) | 746 | self.add(self.vbox) |
712 | 747 | ||
713 | self.info_win = InfoWindow() | 748 | self.info_win = InfoWindow() |
749 | self.text_input_dialog = TextInputDialog('Move to Time', 'how is babby formed?', self) | ||
714 | self.color_dialog = gtk.ColorSelectionDialog('Choose Item Color') | 750 | self.color_dialog = gtk.ColorSelectionDialog('Choose Item Color') |
715 | 751 | ||
716 | self.cur_item_no = None | 752 | self.cur_item_no = None |
717 | 753 | ||
718 | self.set_size_request(MainWindow.WINDOW_WIDTH_REQ, MainWindow.WINDOW_HEIGHT_REQ) | 754 | self.set_size_request(MainWindow.WINDOW_WIDTH_REQ, MainWindow.WINDOW_HEIGHT_REQ) |
719 | 755 | ||
720 | self.set_title('Unit-Trace Visualizer') | 756 | self.set_title('Unit-Trace Visualizer') |
@@ -736,7 +772,7 @@ class MainWindow(gtk.Window): | |||
736 | self.connect_widgets(gwindow) | 772 | self.connect_widgets(gwindow) |
737 | gwindow.show() | 773 | gwindow.show() |
738 | self.notebook.append_page(gwindow, gtk.Label(title)) | 774 | self.notebook.append_page(gwindow, gtk.Label(title)) |
739 | 775 | ||
740 | if self.notebook.get_n_pages() > 0: | 776 | if self.notebook.get_n_pages() > 0: |
741 | self.notebook.get_nth_page(0).grab_focus() | 777 | self.notebook.get_nth_page(0).grab_focus() |
742 | 778 | ||
@@ -750,14 +786,14 @@ class MainWindow(gtk.Window): | |||
750 | def update_sel_changes(self, widget, selected): | 786 | def update_sel_changes(self, widget, selected): |
751 | """Modify the GUI appropriately to reflect a change in selection.""" | 787 | """Modify the GUI appropriately to reflect a change in selection.""" |
752 | self.selected = selected | 788 | self.selected = selected |
753 | 789 | ||
754 | self.cur_item_no = self.notebook.get_nth_page(self.notebook.last_page).get_graph_area() \ | 790 | self.cur_item_no = self.notebook.get_nth_page(self.notebook.last_page).get_graph_area() \ |
755 | .get_graph().all_one_item_selected(selected) | 791 | .get_graph().all_one_item_selected(selected) |
756 | if self.cur_item_no is not None: | 792 | if self.cur_item_no is not None: |
757 | self.colors_item.set_sensitive(True) | 793 | self.colors_item.set_sensitive(True) |
758 | else: | 794 | else: |
759 | self.colors_item.set_sensitive(False) | 795 | self.colors_item.set_sensitive(False) |
760 | 796 | ||
761 | def switch_page(self, widget, page, page_num): | 797 | def switch_page(self, widget, page, page_num): |
762 | if self.notebook.get_nth_page(self.notebook.last_page) is not None: | 798 | if self.notebook.get_nth_page(self.notebook.last_page) is not None: |
763 | old_value = self.notebook.get_nth_page(self.notebook.last_page).get_hadjustment().get_value() | 799 | old_value = self.notebook.get_nth_page(self.notebook.last_page).get_hadjustment().get_value() |
@@ -765,11 +801,28 @@ class MainWindow(gtk.Window): | |||
765 | new_ofs = self.notebook.get_nth_page(page_num).get_graph_area().get_graph().get_origin()[0] | 801 | new_ofs = self.notebook.get_nth_page(page_num).get_graph_area().get_graph().get_origin()[0] |
766 | new_value = old_value - old_ofs + new_ofs | 802 | new_value = old_value - old_ofs + new_ofs |
767 | self.notebook.get_nth_page(page_num).get_hadjustment().set_value(new_value) | 803 | self.notebook.get_nth_page(page_num).get_hadjustment().set_value(new_value) |
804 | unit = self.notebook.get_nth_page(page_num).get_graph_area().get_graph().get_attrs().unit | ||
805 | self.info_win.set_unit(unit) | ||
768 | 806 | ||
769 | self.notebook.last_page = page_num | 807 | self.notebook.last_page = page_num |
770 | 808 | ||
771 | def update_event_description(self, widget, event, msg): | 809 | def update_event_description(self, widget, event): |
772 | self.desc_label.set_text(msg) | 810 | if event is None: |
811 | self.event_label.set_text('') | ||
812 | self.job_run_label.set_text('') | ||
813 | self.job_rd_label.set_text('') | ||
814 | return | ||
815 | |||
816 | unit = self.notebook.get_nth_page(self.notebook.last_page).get_graph_area() \ | ||
817 | .get_graph().get_attrs().unit | ||
818 | self.event_label.set_text(event.str_short(unit)) | ||
819 | job = event.get_job() | ||
820 | if job is None: | ||
821 | self.job_run_label.set_text('') | ||
822 | self.job_rd_label.set_text('') | ||
823 | else: | ||
824 | self.job_run_label.set_text(job.str_run_short(unit)) | ||
825 | self.job_rd_label.set_text(job.str_rd_short(unit)) | ||
773 | 826 | ||
774 | def request_context_menu(self, widget, gdk_event, selected): | 827 | def request_context_menu(self, widget, gdk_event, selected): |
775 | button = 0 | 828 | button = 0 |
@@ -789,23 +842,34 @@ class MainWindow(gtk.Window): | |||
789 | if self.notebook.get_nth_page(i).get_graph_area() is sender: | 842 | if self.notebook.get_nth_page(i).get_graph_area() is sender: |
790 | self.notebook.get_nth_page(i).get_graph_area().refresh_events(sender, old, new, replace) | 843 | self.notebook.get_nth_page(i).get_graph_area().refresh_events(sender, old, new, replace) |
791 | break | 844 | break |
792 | 845 | ||
793 | def move_to_time_activate(self, widget): | 846 | def move_to_time_activate(self, widget): |
794 | dialog = TextInputDialog('Move to Time', 'What time to move to?', self) | 847 | unit = self.notebook.get_nth_page(self.notebook.last_page).get_graph_area() \ |
848 | .get_graph().get_attrs().unit | ||
849 | |||
850 | self.text_input_dialog.set_prompt('What time to move to (default ' + str(unit) + ') ?') | ||
795 | 851 | ||
796 | err = True | 852 | err = True |
797 | while err: | 853 | while err: |
798 | ret = dialog.run() | 854 | ret = self.text_input_dialog.run() |
799 | 855 | ||
800 | if ret == gtk.RESPONSE_ACCEPT: | 856 | if ret == gtk.RESPONSE_ACCEPT: |
801 | err, time = None, None | 857 | err, time = None, None |
802 | try: | 858 | try: |
803 | time = float(dialog.get_input()) | 859 | input_tokens = self.text_input_dialog.get_input().split() |
804 | start, end = self.notebook.get_nth_page(0).get_graph_area().get_schedule().get_time_bounds() | 860 | if len(input_tokens) > 2: |
861 | raise ValueError | ||
862 | |||
863 | if len(input_tokens) > 1: | ||
864 | unit = util.parse_unit(input_tokens[1]) | ||
865 | |||
866 | time = unit.native_to_nsec(float(input_tokens[0])) | ||
867 | start, end = self.notebook.get_nth_page(self.notebook.last_page).get_graph_area() \ | ||
868 | .get_schedule().get_time_bounds() | ||
805 | if time < start or time > end: | 869 | if time < start or time > end: |
806 | err = 'Time out of range!' | 870 | err = 'Time out of range!' |
807 | except ValueError: | 871 | except ValueError: |
808 | err = 'Must input a number!' | 872 | err = 'Must input a number (with an optional unit)!' |
809 | 873 | ||
810 | if not err: | 874 | if not err: |
811 | for i in xrange(0, self.notebook.get_n_pages()): | 875 | for i in xrange(0, self.notebook.get_n_pages()): |
@@ -820,12 +884,12 @@ class MainWindow(gtk.Window): | |||
820 | err) | 884 | err) |
821 | err_dialog.set_title('Input Error') | 885 | err_dialog.set_title('Input Error') |
822 | err_dialog.run() | 886 | err_dialog.run() |
823 | err_dialog.destroy() | 887 | err_dialog.hide() |
824 | 888 | ||
825 | else: | 889 | else: |
826 | break | 890 | break |
827 | 891 | ||
828 | dialog.destroy() | 892 | self.text_input_dialog.hide() |
829 | 893 | ||
830 | def zoom_in_item_activate(self, widget): | 894 | def zoom_in_item_activate(self, widget): |
831 | for i in range(0, self.notebook.get_n_pages()): | 895 | for i in range(0, self.notebook.get_n_pages()): |
@@ -838,13 +902,13 @@ class MainWindow(gtk.Window): | |||
838 | def colors_activate(self, widget): | 902 | def colors_activate(self, widget): |
839 | garea = self.notebook.get_nth_page(self.notebook.last_page).get_graph_area() | 903 | garea = self.notebook.get_nth_page(self.notebook.last_page).get_graph_area() |
840 | graph = garea.get_renderer().get_graph() | 904 | graph = garea.get_renderer().get_graph() |
841 | 905 | ||
842 | 906 | ||
843 | pattern = graph.get_bar_pattern(self.cur_item_no) | 907 | pattern = graph.get_bar_pattern(self.cur_item_no) |
844 | 908 | ||
845 | if len(pattern.get_color_list()) > 1: | 909 | if len(pattern.get_color_list()) > 1: |
846 | print 'striped patterns not yet supported' | 910 | print 'striped patterns not yet supported' |
847 | 911 | ||
848 | r, g, b = pattern.get_color_list()[0] | 912 | r, g, b = pattern.get_color_list()[0] |
849 | colorsel = self.color_dialog.get_color_selection() | 913 | colorsel = self.color_dialog.get_color_selection() |
850 | cur_color = gtk.gdk.Color(int(r * 65535), int(g * 65535), int(b * 65535)) | 914 | cur_color = gtk.gdk.Color(int(r * 65535), int(g * 65535), int(b * 65535)) |
@@ -857,34 +921,34 @@ class MainWindow(gtk.Window): | |||
857 | r, g, b = color.red / 65535.0, color.green / 65535.0, color.blue / 65535.0 | 921 | r, g, b = color.red / 65535.0, color.green / 65535.0, color.blue / 65535.0 |
858 | graph.set_bar_pattern(self.cur_item_no, Pattern([(r, g, b)])) | 922 | graph.set_bar_pattern(self.cur_item_no, Pattern([(r, g, b)])) |
859 | garea.refresh_all() | 923 | garea.refresh_all() |
860 | 924 | ||
861 | self.color_dialog.hide() | 925 | self.color_dialog.hide() |
862 | 926 | ||
863 | def save_item_activate(self, widget): | 927 | def save_item_activate(self, widget): |
864 | ACCEPTED_TYPES = ('png', 'svg') | 928 | ACCEPTED_TYPES = ('png', 'svg') |
865 | 929 | ||
866 | dialog = gtk.FileChooserDialog('Save to Graphics File', self, | 930 | dialog = gtk.FileChooserDialog('Save to Graphics File', self, |
867 | gtk.FILE_CHOOSER_ACTION_SAVE, | 931 | gtk.FILE_CHOOSER_ACTION_SAVE, |
868 | (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, | 932 | (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, |
869 | gtk.STOCK_SAVE, gtk.RESPONSE_ACCEPT)) | 933 | gtk.STOCK_SAVE, gtk.RESPONSE_ACCEPT)) |
870 | 934 | ||
871 | png_filter = gtk.FileFilter() | 935 | png_filter = gtk.FileFilter() |
872 | png_filter.add_mime_type('image/png') | 936 | png_filter.add_mime_type('image/png') |
873 | png_filter.set_name('PNG image (*.png)') | 937 | png_filter.set_name('PNG image (*.png)') |
874 | dialog.add_filter(png_filter) | 938 | dialog.add_filter(png_filter) |
875 | 939 | ||
876 | svg_filter = gtk.FileFilter() | 940 | svg_filter = gtk.FileFilter() |
877 | svg_filter.add_mime_type('image/svg+xml') | 941 | svg_filter.add_mime_type('image/svg+xml') |
878 | svg_filter.set_name('SVG vector image (*.svg)') | 942 | svg_filter.set_name('SVG vector image (*.svg)') |
879 | dialog.add_filter(svg_filter) | 943 | dialog.add_filter(svg_filter) |
880 | 944 | ||
881 | filename = None | 945 | filename = None |
882 | ftype = None | 946 | ftype = None |
883 | while True: | 947 | while True: |
884 | if dialog.run() == gtk.RESPONSE_ACCEPT: | 948 | if dialog.run() == gtk.RESPONSE_ACCEPT: |
885 | filename = dialog.get_filename() | 949 | filename = dialog.get_filename() |
886 | # parse filename for extension | 950 | # parse filename for extension |
887 | 951 | ||
888 | parts = filename.split('.') | 952 | parts = filename.split('.') |
889 | ftype = None | 953 | ftype = None |
890 | if len(parts) == 1: | 954 | if len(parts) == 1: |
@@ -910,7 +974,7 @@ class MainWindow(gtk.Window): | |||
910 | filename = None | 974 | filename = None |
911 | ftype = None | 975 | ftype = None |
912 | break | 976 | break |
913 | 977 | ||
914 | if filename is not None: | 978 | if filename is not None: |
915 | cursor = gtk.gdk.Cursor(gtk.gdk.WATCH) | 979 | cursor = gtk.gdk.Cursor(gtk.gdk.WATCH) |
916 | dialog.get_window().set_cursor(cursor) | 980 | dialog.get_window().set_cursor(cursor) |
@@ -919,9 +983,9 @@ class MainWindow(gtk.Window): | |||
919 | dialog.get_window().set_cursor(None) | 983 | dialog.get_window().set_cursor(None) |
920 | dialog.destroy() | 984 | dialog.destroy() |
921 | gobject.idle_add(idle_callback, dialog) # needed to get the cursor to display | 985 | gobject.idle_add(idle_callback, dialog) # needed to get the cursor to display |
922 | else: | 986 | else: |
923 | dialog.destroy() | 987 | dialog.destroy() |
924 | 988 | ||
925 | def quit_item_activate(self, widget): | 989 | def quit_item_activate(self, widget): |
926 | self.destroy() | 990 | self.destroy() |
927 | 991 | ||