autopilot-gtk-1.6.0/0000775000000000000000000000000013576175045011226 5ustar autopilot-gtk-1.6.0/tests/0000775000000000000000000000000013576175035012367 5ustar autopilot-gtk-1.6.0/tests/hello_color.py0000775000000000000000000000347613576175035015257 0ustar #!/usr/bin/python3 import sys import os.path import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk class HelloColorApp(Gtk.Application): def __init__(self): self.widgets = Gtk.Builder.new() self.widgets.add_from_file((os.path.join(os.path.dirname(sys.argv[0]), 'hello_color.ui'))) assert self.widgets.connect_signals(self) is None def run(self): self.widgets.get_object('window_app').show() Gtk.main() def on_quit(self, *args): Gtk.main_quit() def on_file_open(self, *args): md = Gtk.FileChooserDialog('Select a file..', parent=self.widgets.get_object('window_app'), buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.OK)) result = md.run() md.hide() if result == Gtk.ResponseType.OK: self.widgets.get_object('label_status').set_text('Loaded %s' % md.get_filenames()[0]) def on_button_greet(self, *args): name = self.widgets.get_object('entry_name').get_text() color = self.widgets.get_object('entry_color').get_text() md = Gtk.MessageDialog(message_type=Gtk.MessageType.INFO, buttons=Gtk.ButtonsType.CLOSE, text='Hello %s, you like %s.' % (name, color)) md.run() md.hide() def on_button_clear(self, *args): self.widgets.get_object('entry_name').set_text('') self.widgets.get_object('entry_color').set_text('') self.widgets.get_object('label_status').set_text('') def on_about(self, *args): d = self.widgets.get_object('dialog_about') d.run() d.hide() if __name__ == '__main__': HelloColorApp().run() autopilot-gtk-1.6.0/tests/autopilot/0000775000000000000000000000000013576175035014407 5ustar autopilot-gtk-1.6.0/tests/autopilot/tests/0000775000000000000000000000000013576175035015551 5ustar autopilot-gtk-1.6.0/tests/autopilot/tests/test_gnome_app.py0000664000000000000000000000365513576175035021140 0ustar # blackbox testing of autopilot API against gnome-calculator # Author: Martin Pitt # Copyright (C) 2013 Canonical Ltd # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3 as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from autopilot.testcase import AutopilotTestCase from autopilot.matchers import Eventually from testtools.matchers import Equals from fixtures import EnvironmentVariable class GnomeAppTest(AutopilotTestCase): """Test autopilot against an actual GNOME application""" def setUp(self): super(GnomeAppTest, self).setUp() patched_env = EnvironmentVariable('LANGUAGE', '') patched_env = EnvironmentVariable('LANG', '') patched_env = EnvironmentVariable('LC_MESSAGES', 'C') self.useFixture(patched_env) self.app = self.launch_test_application('gnome-calculator') def test_builder_button(self): """Find button by builder ID""" l = self.app.select_single(BuilderName='calc_result_button') self.assertNotEqual(l, None) self.assertEqual(l.visible, True) self.assertEqual(l.label, '=') def test_calc(self): """Run a calculation""" display = self.app.select_single(BuilderName='displayitem') self.mouse.click_object(display) self.assertThat(display.buffer, Equals('')) self.keyboard.type('1+1') self.keyboard.press_and_release('Enter') self.assertThat(display.buffer, Eventually(Equals('2'))) autopilot-gtk-1.6.0/tests/autopilot/tests/test_xpath_query.py0000664000000000000000000001052113576175035021532 0ustar # blackbox testing of autopilot API against our hello_color.py test GTK program # Author: Martin Pitt # Copyright (C) 2013 Canonical Ltd # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3 as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import os.path import unittest from autopilot.testcase import AutopilotTestCase tests_dir = os.path.dirname(os.path.dirname(os.path.dirname( os.path.realpath(__file__)))) test_app = os.path.join(tests_dir, 'hello_color.py') class XPathQueryTest(AutopilotTestCase): """XPath queries""" def setUp(self): super(XPathQueryTest, self).setUp() self.app = self.launch_test_application(test_app, app_type='gtk') def xtest_have_path(self): """All children have a unique path""" widgets = set() self._get_widgets(self.app, widgets) seen_paths = set() for widget in widgets: path = widget.get_class_query_string() self.assertNotIn(path, seen_paths) seen_paths.add(path) # we can resolve the path back to the widget state = self.app.get_state_by_path(path) # state is an array with one (path, props) element props = state[0][1] self.assertEqual(props['id'], widget.id) self.assertEqual(props['visible'], widget.visible) def xtest_select_full_path(self): """Select widgets with full XPath""" # three buttons in main dialog's ButtonBox state = self.app.get_state_by_path('/Root/GtkWindow/GtkBox/GtkButtonBox/GtkButton') self.assertEqual(len(state), 3) labels = [str(props[1]['label']) for props in state] labels.sort() self.assertEqual(labels, ['Greet', 'gtk-delete', 'gtk-quit']) # select button with particular label for l in ['Greet', 'gtk-delete', 'gtk-quit']: state = self.app.get_state_by_path('/Root/GtkWindow/GtkBox/GtkButtonBox/GtkButton[label=%s]' % l) self.assertEqual(len(state), 1) self.assertEqual(state[0][1]['label'], l) def xtest_select_path_pattern(self): """Select widgets with XPath path pattern""" # three buttons in main dialog's ButtonBox state = self.app.get_state_by_path('//GtkWindow//GtkButton') self.assertEqual(len(state), 3) labels = [str(props[1]['label']) for props in state] labels.sort() self.assertEqual(labels, ['Greet', 'gtk-delete', 'gtk-quit']) # at least four buttons in the whole tree state = self.app.get_state_by_path('/Root//GtkButton') self.assertGreaterEqual(len(state), 4) # FIXME: Fix this test, it fails with: # AttributeError: Class 'Root' has no attribute 'get_state_by_path' @unittest.expectedFailure def test_select_by_attribute(self): """Select widgets with attribute pattern""" state = self.app.get_state_by_path('//*[label="gtk-delete"]') self.assertEqual(len(state), 1, state) self.assertEqual(state[0][1]['label'], [0, 'gtk-delete']) self.assertTrue(state[0][0].endswith('/GtkButton'), state[0][0]) # https://launchpad.net/bugs/1179806 # TODO: Make this pass! @unittest.expectedFailure def test_select_by_attribute_spaces(self): """Select widgets with attribute pattern containing spaces""" for state_str in ('//*[label="Hello\\x20Color!"]', '//*[label="Hello Color!"]'): state = self.app.get_state_by_path(state_str) self.assertEqual(len(state), 1, str(state)) self.assertEqual(state[0][1]['label'], 'Hello Color!') self.assertTrue(state[0][0].endswith('/GtkLabel'), state[0][0]) @classmethod def _get_widgets(klass, obj, widget_set): """Recursively add all children of obj to widget_set""" for c in obj.get_children(): widget_set.add(c) klass._get_widgets(c, widget_set) autopilot-gtk-1.6.0/tests/autopilot/tests/test_properties.py0000664000000000000000000001277013576175035021365 0ustar # blackbox testing of autopilot API against our hello_color.py test GTK program # Author: Martin Pitt # Copyright (C) 2013 Canonical Ltd # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3 as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import os.path import unittest from autopilot.testcase import AutopilotTestCase tests_dir = os.path.dirname(os.path.dirname(os.path.dirname( os.path.realpath(__file__)))) test_app = os.path.join(tests_dir, 'hello_color.py') class PropertyTest(AutopilotTestCase): """Widget properties""" def setUp(self): super(PropertyTest, self).setUp() self.app = self.launch_test_application(test_app, app_type='gtk') def test_gtk_builder_name(self): """GtkBuilder name lookup""" w = self.app.select_single(BuilderName='button_greet') self.assertNotEqual(w, None) self.assertEqual(w.label, 'Greet') w = self.app.select_single(BuilderName='button_quit') self.assertNotEqual(w, None) self.assertEqual(w.label, 'gtk-quit') w = self.app.select_single(BuilderName='entry_color') self.assertNotEqual(w, None) def test_button(self): """GtkButton properties""" btn_greet = self.app.select_single('GtkButton', label='Greet') self.assertNotEqual(btn_greet, None) btn_quit = self.app.select_single('GtkButton', label='gtk-quit') self.assertNotEqual(btn_quit, None) self.assertEqual(btn_greet.use_stock, False) self.assertEqual(btn_quit.use_stock, True) # only GtkButton, GtkFileChooserButton, and GtkComboBox have # focus-on-click, and we don't use the latter two self.assertEqual(btn_greet.focus_on_click, True) self.assertEqual(btn_quit.focus_on_click, True) # all buttons are visible and thus should have a rect self.assertTrue(btn_greet.visible) self.assertTrue(btn_quit.visible) self.assertEqual(len(btn_greet.globalRect), 4) self.assertEqual(len(btn_quit.globalRect), 4) # all our buttons have a GtkBuilder ID self.assertEqual(btn_greet.BuilderName, 'button_greet') self.assertEqual(btn_quit.BuilderName, 'button_quit') def test_entry(self): """GtkEntry properties""" entry_name = self.app.select_single(BuilderName='entry_name') entry_color = self.app.select_single(BuilderName='entry_color') self.assertTrue(entry_name.visible) self.assertTrue(entry_color.visible) # the entries should have the same size and x alignment self.assertEqual(entry_name.globalRect[0], entry_color.globalRect[0]) self.assertEqual(entry_name.globalRect[2:], entry_color.globalRect[2:]) # FIXME: This isn't necessary for real X, but under Xvfb there is no # default focus sometimes if not entry_name.has_focus: self.mouse.click_object(entry_name) # the color entry is below the name entry self.assertLess(entry_name.globalRect[1], entry_color.globalRect[1]) # first entry has default focus self.assertEqual(entry_name.has_focus, True) self.assertEqual(entry_color.has_focus, False) # both entries are empty by default self.assertEqual(entry_name.text, '') self.assertEqual(entry_color.text, '') # text-length is an unique property for GtkEntry self.assertEqual(entry_name.text_length, 0) self.assertEqual(entry_color.text_length, 0) def test_enum_flags_properties(self): '''enum and flags properties''' # enum btn_greet = self.app.select_single('GtkButton', label='Greet') self.assertEqual(btn_greet.relief, 'GTK_RELIEF_NORMAL') self.assertEqual(btn_greet.resize_mode, 'GTK_RESIZE_PARENT') res = self.app.select_many(relief='GTK_RELIEF_NORMAL', visible=True) self.assertGreaterEqual(len(res), 3) self.assertIn('Button', str(type(res[0]))) # flags self.assertGreaterEqual(btn_greet.events, 0) res = self.app.select_many('GtkButton', events=btn_greet.events) self.assertGreater(len(res), 0) def test_textview_properties(self): """GtkTextView properties""" t = self.app.select_single(BuilderName='textview_demo') self.assertNotEqual(t, None) self.assertEqual(t.editable, True) self.assertEqual(t.overwrite, False) # the buffer property points to a GtkTextBuffer object, which we want # to translate to a plain string self.assertEqual(t.buffer, 'This is a test application.') # select by buffer contents w = self.app.select_single(buffer='This is a test application.') self.assertEqual(w.BuilderName, 'textview_demo') def test_stress(self): """Query lots widgets in a tight loop""" for i in range(300): w = self.app.select_single(BuilderName='button_greet') self.assertEqual(w.label, 'Greet') w = self.app.select_single('GtkButton', label='gtk-quit') self.assertEqual(w.use_stock, True) autopilot-gtk-1.6.0/tests/autopilot/tests/test_widget_tree.py0000664000000000000000000001555713576175035021501 0ustar # blackbox testing of autopilot API against our hello_color.py test GTK program # Author: Martin Pitt # Copyright (C) 2013 Canonical Ltd # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3 as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import os.path import unittest from autopilot.introspection.dbus import StateNotFoundError from autopilot.testcase import AutopilotTestCase from testtools.matchers import raises tests_dir = os.path.dirname(os.path.dirname(os.path.dirname( os.path.realpath(__file__)))) test_app = os.path.join(tests_dir, 'hello_color.py') class WidgetTreeTest(AutopilotTestCase): """Widget tree iteration and search""" def setUp(self): super(WidgetTreeTest, self).setUp() self.app = self.launch_test_application(test_app, app_type='gtk') def test_get_children_recursive(self): """Recursive get_children() This should not crash, and deliver valid widgets. """ widgets = set() self._get_widgets(self.app, widgets) for c in widgets: self.assertIn('.Gtk', str(type(c))) self.assertGreaterEqual(c.id, 0) # uncomment this to get a dump of all widgets and properties #print(type(c)) #for p in c.get_properties(): # print ' ', p, repr(getattr(c, p)) def test_get_children_by_type(self): # multiple instances res = self.app.get_children_by_type('GtkWindow') self.assertGreaterEqual(len(res), 3) self.assertIn('.GtkWindow', str(type(res[0]))) # one qualified instance res = self.app.get_children_by_type('GtkWindow', Children=['GtkBox']) self.assertGreaterEqual(len(res), 1) # no instances self.assertEqual(self.app.get_children_by_type('GtkTable'), []) def test_select_single_unique(self): """select_single() on widget types with only one instance""" for wtype in ('GtkMenuBar', 'GtkAboutDialog'): w = self.app.select_single(wtype) self.assertIn('.' + wtype, str(type(w))) def test_select_single_nonunique(self): """select_single() on widget types with multiple instances""" # we have more than one instance of these for wtype in ('GtkButton', 'GtkEntry'): self.assertRaises(ValueError, self.app.select_single, wtype) # we have no instances of these for wtype in ('GtkTable', 'NonExistent'): RaisedStateNotFound = False try: self.app.select_single(wtype) except StateNotFoundError: RaisedStateNotFound = True self.assertTrue(RaisedStateNotFound) # qualified: visible property is not unique self.assertRaises(ValueError, self.app.select_single, 'GtkButton', visible=True) # qualified: label property is unique within GtkButton w = self.app.select_single('GtkButton', label='gtk-quit') self.assertIn('.GtkButton', str(type(w))) self.assertEqual(w.label, 'gtk-quit') def test_select_single_noclass(self): """select_single() without specifying a class""" # gtk-delete label is unique to our Button w = self.app.select_single(label='gtk-delete') self.assertIn('.GtkButton', str(type(w))) self.assertEqual(w.label, 'gtk-delete') # gtk-quit label is not unique globally, it's also a menu item self.assertRaises(ValueError, self.app.select_single, label='gtk-quit') # ... but it is unique for focussable widgets (menus don't allow that) w = self.app.select_single(label='gtk-quit', can_focus=True) self.assertIn('.GtkButton', str(type(w))) self.assertEqual(w.label, 'gtk-quit') def test_select_many_string(self): """select_many() with string properties""" # by class, unqualified, multiple instances res = self.app.select_many('GtkButton') # we have three in our main window, plus some in the about dialog self.assertGreaterEqual(len(res), 3) self.assertIn('.GtkButton', str(type(res[0]))) # .. but exactly three in the main window main_window = self.app.select_single('GtkWindow', Children=['GtkBox'], visible=True) res = main_window.select_many('GtkButton') self.assertEqual(len(res), 3) # by class, unqualified, single instance res = self.app.select_many('GtkMenuBar') self.assertEqual(len(res), 1) self.assertIn('.GtkMenuBar', str(type(res[0]))) # by class, unqualified, no instance res = self.app.select_many('GtkTable') self.assertEqual(res, []) # by class, qualified res = self.app.select_many('GtkButton', label='Greet') self.assertEqual(len(res), 1) self.assertIn('.GtkButton', str(type(res[0]))) self.assertEqual(res[0].label, 'Greet') # untyped res = self.app.select_many(label='gtk-delete') self.assertEqual(len(res), 1) self.assertIn('.GtkButton', str(type(res[0]))) self.assertEqual(res[0].label, 'gtk-delete') res = self.app.select_many(label='gtk-quit') # button and menu item self.assertEqual(len(res), 2) def test_select_int(self): """select_*() with int properties""" # with class res = self.app.select_many('GtkButtonBox', border_width=5) self.assertEqual(len(res), 1) self.assertNotEqual(self.app.select_single('GtkButtonBox', border_width=5), None) # without class res = self.app.select_many(border_width=5) self.assertGreater(len(res), 2) self.assertNotEqual(self.app.select_single(border_width=2), None) def test_select_bool(self): """select_*() with boolean properties""" # with class res = self.app.select_many('GtkButton', visible=True) self.assertGreater(len(res), 2) res = self.app.select_many('GtkAboutDialog', visible=False) self.assertGreater(len(res), 0) # without class res = self.app.select_many(visible=True) self.assertGreater(len(res), 5) res = self.app.select_many(visible=False) self.assertGreater(len(res), 4) @classmethod def _get_widgets(klass, obj, widget_set): """Recursively add all children of obj to widget_set""" for c in obj.get_children(): widget_set.add(c) klass._get_widgets(c, widget_set) autopilot-gtk-1.6.0/tests/autopilot/tests/test_actions.py0000664000000000000000000001536213576175035020631 0ustar # blackbox testing of autopilot API against our hello_color.py test GTK program # Author: Martin Pitt # Copyright (C) 2013 Canonical Ltd # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3 as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import os.path import os import time from autopilot.testcase import AutopilotTestCase from autopilot.introspection.dbus import StateNotFoundError from autopilot.matchers import Eventually from testtools.matchers import Equals, NotEquals, raises tests_dir = os.path.dirname(os.path.dirname(os.path.dirname( os.path.realpath(__file__)))) test_app = os.path.join(tests_dir, 'hello_color.py') class ActionsTest(AutopilotTestCase): """Test performing actions in the UI and verify results""" def setUp(self): super(ActionsTest, self).setUp() # we want to test the position of GtkMenuItems here, disable global menubar os.environ['UBUNTU_MENUPROXY'] = '0' self.app = self.launch_test_application(test_app, app_type='gtk') def test_greeting_keyboard(self): """Greeting with keyboard navigation""" entry_name = self.app.select_single(BuilderName='entry_name') entry_color = self.app.select_single(BuilderName='entry_color') # FIXME: This isn't necessary for real X, but under Xvfb there is no # default focus sometimes if not entry_name.has_focus: self.mouse.click_object(entry_name) # type in name and color self.keyboard.type('Joe') self.keyboard.press_and_release('Tab') self.keyboard.type('red') # entries should now have the typed text self.assertThat(entry_name.text, Eventually(Equals('Joe'))) self.assertThat(entry_color.text, Eventually(Equals('red'))) # should not have any dialogs self.assertThat( lambda: self.app.select_single('GtkMessageDialog'), raises(StateNotFoundError) ) # focus and activate the "Greet" button self.keyboard.press_and_release('Tab') self.keyboard.press_and_release('Enter') # should get the greeting dialog md = self.app.wait_select_single('GtkMessageDialog', visible=True) # we expect the message dialog to show the corresponding greeting self.assertNotEqual(md.select_single('GtkLabel', label=u'Hello Joe, you like red.'), None) # close the dialog self.keyboard.press_and_release('Enter') self.assertThat( lambda: self.app.select_single('GtkMessageDialog', visible=True), raises(StateNotFoundError) ) def test_greeting_mouse(self): """Greeting with mouse navigation""" entry_name = self.app.select_single(BuilderName='entry_name') entry_color = self.app.select_single(BuilderName='entry_color') # FIXME: This isn't necessary for real X, but under Xvfb there is no # default focus sometimes if not entry_name.has_focus: self.mouse.click_object(entry_name) # type in name and color self.keyboard.type('Joe') self.mouse.click_object(entry_color) self.keyboard.type('blue') # entries should now have the typed text self.assertThat(entry_name.text, Eventually(Equals('Joe'))) self.assertThat(entry_color.text, Eventually(Equals('blue'))) # should not have any dialogs self.assertThat( lambda: self.app.select_single('GtkMessageDialog'), raises(StateNotFoundError) ) # focus and activate the "Greet" button btn = self.app.select_single('GtkButton', label='Greet') self.assertNotEqual(btn, None) self.mouse.click_object(btn) # should get the greeting dialog md = self.app.wait_select_single('GtkMessageDialog', visible=True) # we expect the message dialog to show the corresponding greeting self.assertNotEqual(md.select_single('GtkLabel', label=u'Hello Joe, you like blue.'), None) # close the dialog btn = md.wait_select_single('GtkButton', visible=True) time.sleep(1) self.mouse.click_object(btn) # We don't have Eventually(raises(... support, so wait until the second # assert should be okay to test. self.assertThat(md.visible, Eventually(Equals(False))) self.assertThat( lambda: self.app.select_single('GtkMessageDialog', visible=True), raises(StateNotFoundError) ) def test_clear(self): """Using Clear button with mouse""" # type in name and color self.keyboard.type('Joe') self.keyboard.press_and_release('Tab') self.keyboard.type('blue') # clear btn = self.app.select_single('GtkButton', label='gtk-delete') self.mouse.click_object(btn) # entries should be clear now entries = self.app.select_many('GtkEntry') self.assertEqual(len(entries), 2) for e in entries: self.assertThat(e.text, Eventually(Equals(''))) def test_menu(self): """Browse the menu""" file_menu = self.app.select_single('GtkMenuItem', label='_File') help_menu = self.app.select_single('GtkMenuItem', label='_Help') self.assertNotEqual(file_menu, None) self.assertNotEqual(help_menu, None) # the top-level menus should be visible and thus have a rect for m in (file_menu, help_menu): self.assertGreaterEqual(m.globalRect[0], 0) self.assertGreaterEqual(m.globalRect[1], 0) self.assertGreater(m.globalRect[2], 0) self.assertGreater(m.globalRect[3], 0) # the submenus are not visible by default m = self.app.select_single('GtkImageMenuItem', label='gtk-open') self.assertFalse(hasattr(m, 'globalRect')) # after opening, submenus should become visible self.mouse.click_object(file_menu) m = self.app.wait_select_single('GtkImageMenuItem', label='gtk-open', visible=True) self.assertGreaterEqual(m.globalRect[0], 0) self.assertGreaterEqual(m.globalRect[1], 0) self.assertGreater(m.globalRect[2], 0) self.assertGreater(m.globalRect[3], 0) autopilot-gtk-1.6.0/tests/autopilot/tests/__init__.py0000664000000000000000000000000013576175035017650 0ustar autopilot-gtk-1.6.0/tests/hello_color.ui0000664000000000000000000002760313576175035015237 0ustar False 5 dialog Hello Color! (C) 2013 Canonical Ltd. Martin Pitt gpl-3-0 False TextView Demo True False True False textbuffer_demo This is a test application. False Hello Color True False vertical True False True False _File True True False gtk-open True False True True True False gtk-quit True False True True True False _Help True True False gtk-about True False True True False True 0 True False start 5 5 5 5 5 5 True False Name 0 0 1 1 True False Color 0 1 1 1 True True True 1 0 1 1 True True 1 1 1 1 True True 1 True False 0 5 10 False True 2 True 5 False 10 True end 5 Greet True True True False True 0 gtk-delete True True True True False True 1 gtk-quit True True True True right False True 2 False True 3 autopilot-gtk-1.6.0/CMakeLists.txt0000664000000000000000000000062513576175035013770 0ustar cmake_minimum_required(VERSION 2.6) project(autopilot-gtk) include (GNUInstallDirs) set (VERSION 0.2) set (CMAKE_CXX_FLAGS "-DGNOME_DESKTOP_USE_UNSTABLE_API -std=c++11 -fno-permissive") INCLUDE(FindPkgConfig) add_subdirectory(lib) enable_testing() add_test(autopilot sh -c "cd ${CMAKE_CURRENT_SOURCE_DIR}/tests/autopilot; GTK_PATH=${CMAKE_CURRENT_BINARY_DIR}/lib autopilot3-sandbox-run -a -v tests") autopilot-gtk-1.6.0/debian/0000775000000000000000000000000013576175035012447 5ustar autopilot-gtk-1.6.0/debian/copyright0000664000000000000000000000305213576175035014402 0ustar Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: autopilot-gtk Source: http://launchpad.net/autopilot-gtk Files: * Copyright: 2012 Canonical Ltd. License: GPL-3 This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3, as published by the Free Software Foundation. . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. . On Debian systems, the complete text of the GNU General Public License version 3 can be found in "/usr/share/common-licenses/GPL-3". Files: debian/* Copyright: 2012 Allan LeSage License: GPL-2 This package is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2, as published by the Free Software Foundation. . This package is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. . You should have received a copy of the GNU General Public License along with this program. If not, see . On Debian systems, the complete text of the GNU General Public License version 2 can be found in "/usr/share/common-licenses/GPL-2". autopilot-gtk-1.6.0/debian/source/0000775000000000000000000000000013576175035013747 5ustar autopilot-gtk-1.6.0/debian/source/format0000664000000000000000000000000413576175035015154 0ustar 1.0 autopilot-gtk-1.6.0/debian/control0000664000000000000000000000322013576175035014047 0ustar Source: autopilot-gtk Priority: extra Maintainer: Ubuntu Developers XSBC-Original-Maintainer: Allan LeSage Build-Depends: autopilot-desktop (>= 1.6), bamfdaemon, at-spi2-core, cmake, dbus-x11, debhelper (>= 9), gnome-calculator, gsettings-desktop-schemas, gnome-icon-theme-symbolic, libglib2.0-dev, libgtk-3-dev, libxpathselect-dev (>= 1.4), pkg-config, python-evdev, python-gi, xvfb, light-themes Standards-Version: 4.4.1 Section: libs Homepage: https://launchpad.net/autopilot-gtk # If you aren't a member of ~autopilot but need to upload # packaging changes, just go ahead. ~autopilot will notice # and sync up the code again. Vcs-Git: https://git.launchpad.net/autopilot-gtk Vcs-Browser: https://git.launchpad.net/autopilot-gtk XS-Testsuite: autopkgtest Package: libautopilot-gtk Section: libs Architecture: any Multi-Arch: same Pre-Depends: ${misc:Pre-Depends}, Depends: python3-autopilot (>= 1.6), ${misc:Depends}, ${shlibs:Depends}, Replaces: autopilot-gtk, libautopilot-gtk-dev, libautopilot-gtk0, Conflicts: autopilot-gtk, libautopilot-gtk-dev, libautopilot-gtk0, Provides: autopilot-gtk, libautopilot-gtk0, Description: Makes GTK+ applications introspectable by autopilot. This allows autopilot to test any existing GTK+ application, without having to rebuild the application under test. autopilot-gtk-1.6.0/debian/rules0000775000000000000000000000101413576175035013523 0ustar #!/usr/bin/make -f #export DH_VERBOSE=1 export DPKG_GENSYMBOLS_CHECK_LEVEL = 4 %: dh $@ override_dh_auto_test: ifeq (, $(findstring nocheck, $(DEB_BUILD_OPTIONS))) mkdir -p debian/tmp/home/run env HOME=$(CURDIR)/debian/tmp/home XDG_RUNTIME_DIR=$(CURDIR)/debian/tmp/home/run \ xvfb-run -a -e $(CURDIR)/debian/tmp/X.log dh_auto_test || \ { echo "==== X.org log ===="; cat $(CURDIR)/debian/tmp/X.log; false; } endif override_dh_install: dh_install --fail-missing override_dh_makeshlibs: dh_makeshlibs -V autopilot-gtk-1.6.0/debian/compat0000664000000000000000000000000213576175035013645 0ustar 9 autopilot-gtk-1.6.0/debian/tests/0000775000000000000000000000000013576175035013611 5ustar autopilot-gtk-1.6.0/debian/tests/control0000664000000000000000000000046713576175035015223 0ustar Tests: autopilot Depends: @, autopilot-desktop (>= 1.6), bamfdaemon, at-spi2-core, xvfb, dbus-x11, gnome-calculator, gsettings-desktop-schemas, gnome-icon-theme-symbolic, python3-gi, gir1.2-gtk-3.0, light-themes autopilot-gtk-1.6.0/debian/tests/autopilot0000664000000000000000000000011013576175035015544 0ustar #!/bin/sh set -eu cd tests/autopilot autopilot3-sandbox-run -a -v tests autopilot-gtk-1.6.0/debian/changelog0000664000000000000000000003245013576175035014325 0ustar autopilot-gtk (1.6.0) focal; urgency=medium * Remove the dependency on python2 version of autopilot (LP: #1856574) * Update the dependencies to python3 version of autopilot. * Fixed the testsuite. * Bump version number and align it with autopilot * Update Standards-Version to 4.4.1 -- Jean-Baptiste Lallement Tue, 17 Dec 2019 07:55:05 +0100 autopilot-gtk (1.4+15.10.20150826-0ubuntu2) cosmic; urgency=medium * tests/hello_color.ui: Set a border-width on the GtkButtonBox. The testsuite is trying to select all GtkButtonBoxes with border-width equal to 5 without explicitly construcitng one. This worked fine with Ambiance, but now that the default theme is Yaru nothing matches any more, since presumably this value is different there. Ideally the testsuite should be independent of the theme, so we fix this bug by making the test program's .ui file set a border-width of 5 on the GtkButtonBox. -- Iain Lane Wed, 05 Sep 2018 16:38:14 +0100 autopilot-gtk (1.4+15.10.20150826-0ubuntu1) wily; urgency=medium [ CI Train Bot ] * New rebuild forced. [ Iain Lane ] * Wait until the dialog actually goes away before checking for its disappearance to fix failing test. -- CI Train Bot Wed, 26 Aug 2015 20:34:29 +0000 autopilot-gtk (1.4+15.04.20141218-0ubuntu1) vivid; urgency=low [ Iain Lane ] * debian/tests/control: Test-Depend on light-themes. The tests check some properties of the Ubuntu theme - ensure it's installed. -- Ubuntu daily release Thu, 18 Dec 2014 17:05:15 +0000 autopilot-gtk (1.4+14.10.20140526-0ubuntu1) utopic; urgency=low [ Martin Pitt ] * Update build and test deps for autopilot-legacy. Replace gnome- system-log test with gnome-calculator test . [ Ubuntu daily release ] * New rebuild forced -- Ubuntu daily release Mon, 26 May 2014 10:04:31 +0000 autopilot-gtk (1.4+14.04.20140107-0ubuntu2) trusty; urgency=medium * No-change rebuild against trusty's xpathselect. The previous auto-upload was built against the PPA's xpathselect which isn't in trusty yet, making this uninstallable. -- Martin Pitt Wed, 08 Jan 2014 07:30:56 +0100 autopilot-gtk (1.4+14.04.20140107-0ubuntu1) trusty; urgency=low [ Martin Pitt ] * Tone down "unsupported type" warning into a debug message. (LP: #1250452) * Add stress test case for querying lots of properties in a tight loop. (LP: #1266689) [ Ubuntu daily release ] * Automatic snapshot from revision 70 -- Ubuntu daily release Tue, 07 Jan 2014 22:47:25 +0000 autopilot-gtk (1.4+14.04.20131218-0ubuntu2) trusty; urgency=medium * No-change rebuild against trusty's xpathselect. The previous auto-upload was built against the PPA's xpathselect which isn't in trusty yet, making this uninstallable. -- Martin Pitt Thu, 19 Dec 2013 07:08:09 +0100 autopilot-gtk (1.4+14.04.20131218-0ubuntu1) trusty; urgency=low [ Martin Pitt ] * Fix tests for GTK 3.10. * Avoid unnecessary, inefficient, and crash-prone temporary std::strings. (LP: #1261685) * Respect DEB_BUILD_OPTIONS=nocheck. Add autopkgtest. Add missing at- spi2-core test dependency (caused tests to run 20 min instead of 40 s). [ Ubuntu daily release ] * Automatic snapshot from revision 66 -- Ubuntu daily release Wed, 18 Dec 2013 18:40:27 +0000 autopilot-gtk (1.4+14.04.20131128.1-0ubuntu1) trusty; urgency=low [ Martin Pitt ] * Drop generated GDBus sources from bzr and generate them during build. * Avoid unnecessary string duplication when matching properties. This also fixes a rare crash when cleaning up the temporary string object. (LP: #1254996) [ Mathieu Trudel-Lapierre ] * Fix source format: make it 1.0. [ Timo Jyrinki ] * Wrap-and-sort dependencies, remove trailing whitespace. [ Ubuntu daily release ] * Automatic snapshot from revision 62 -- Ubuntu daily release Thu, 28 Nov 2013 10:03:59 +0000 autopilot-gtk (1.4+14.04.20131106.1-0ubuntu1) trusty; urgency=low [ Thomi Richards ] * Update packaging details so upgrading from 1.3 -> 1.4 is seamless. (LP: #1227797) * Make autopilot-gtk print the wire protocol version when it start up. (LP: #1248293) [ Martin Pitt ] * Build-depend on autopilot >= 1.4 to ensure protocol compatibility in tests [ Ubuntu daily release ] * Automatic snapshot from revision 57 -- Ubuntu daily release Wed, 06 Nov 2013 10:03:24 +0000 autopilot-gtk (1.4-0ubuntu1) saucy; urgency=low [ Thomi Richards ] * Version bump, updatedx to new xpathselect API. -- Thomi Richards Thu, 15 Aug 2013 15:12:39 +1200 autopilot-gtk (1.3+14.04.20130912ubuntu.unity.next-0ubuntu1) saucy; urgency=low * Automatic snapshot from revision 52 (ubuntu-unity/next) -- Ubuntu daily release Thu, 12 Sep 2013 22:03:46 +0000 autopilot-gtk (1.3+13.10.20130628-0ubuntu1) saucy; urgency=low [ Martin Pitt ] * Handle enum and flags properties. (LP: #1193342). (LP: #1193342) * Expose GtkBuilder widget identifiers as "BuilderName" property. (LP: #1082391). (LP: #1082391) * This fixes the two test failures on raring which Francis saw in https://code.launchpad.net/~pitti/autopilot-gtk/add- tests/+merge/171036/comments/382574 I also sneaked in an unrelated, but trivial change for dropping a leftover debugging statement, in the interest of saving human reviewer and builder resources. * Support GtkTextBuffer properties, to introspect GtkTextView contents. (LP: #1194371) [ Ubuntu daily release ] * Automatic snapshot from revision 51 -- Ubuntu daily release Fri, 28 Jun 2013 00:01:10 +0000 autopilot-gtk (1.3+13.10.20130627-0ubuntu1) saucy; urgency=low [ Martin Pitt ] * Add make test/ctest integration, and run tests during package build. * Add integration test suite (LP: #1083612). (LP: #1083612) [ Alberto Mardegan ] * Initialize rect fields to -1 This makes the globalRect variable return negative values (for some reason, not -1 but -2147483648) when the rectangle is offscreen. (LP: #1176234) [ Ubuntu daily release ] * Automatic snapshot from revision 46 -- Ubuntu daily release Thu, 27 Jun 2013 00:01:15 +0000 autopilot-gtk (1.3daily13.06.05-0ubuntu1) saucy; urgency=low [ Alberto Mardegan ] * Export the ATK objects hierarchy as well AtkObject interfaces are meant for accessibility, and expose more information which can be useful for automated testing. For instance, it is possible to enumerate and introspect all the cells in a GtkTreeView. This patch exposes the ATK objects hierarchies as children of the root node; the existing GtkWidget hierarchy is left untouched, and can still be used. . (LP: #1160827) [ Thomi Richards ] * fix property searching. (LP: #1175738) * Fix crashing bug. (LP: #1177161) * This change fixes an issue with queries that look for gtk windows matching a particular property value. A set of 2 tests has been added to verify the queries that were otherwise failing with a void return set. [ Christopher Lee ] * Add GetVersion to the DBus introspection. [ David Barth ] * This change fixes an issue with queries that look for gtk windows matching a particular property value. A set of 2 tests has been added to verify the queries that were otherwise failing with a void return set. [ Allan LeSage ] * This change fixes an issue with queries that look for gtk windows matching a particular property value. A set of 2 tests has been added to verify the queries that were otherwise failing with a void return set. [ Ubuntu daily release ] * Automatic snapshot from revision 42 -- Ubuntu daily release Wed, 05 Jun 2013 07:08:46 +0000 autopilot-gtk (1.3daily13.05.24ubuntu.unity.next-0ubuntu1) raring; urgency=low [ Thomi Richards ] * This change fixes an issue with queries that look for gtk windows matching a particular property value. A set of 2 tests has been added to verify the queries that were otherwise failing with a void return set. [ Allan LeSage ] * This change fixes an issue with queries that look for gtk windows matching a particular property value. A set of 2 tests has been added to verify the queries that were otherwise failing with a void return set. [ David Barth ] * This change fixes an issue with queries that look for gtk windows matching a particular property value. A set of 2 tests has been added to verify the queries that were otherwise failing with a void return set. [ Ubuntu daily release ] * Automatic snapshot from revision 41 (ubuntu-unity/next) -- Ubuntu daily release Fri, 24 May 2013 00:01:41 +0000 autopilot-gtk (1.3daily13.05.09ubuntu.unity.next-0ubuntu1) raring; urgency=low * Automatic snapshot from revision 39 (ubuntu-unity/next) -- Ubuntu daily release Thu, 09 May 2013 00:00:58 +0000 autopilot-gtk (1.3daily13.05.08ubuntu.unity.next-0ubuntu1) raring; urgency=low [ Thomi Richards ] * Autopilot-gtk crashes when a query returns no results. (LP: #1177161) [ Ubuntu daily release ] * Automatic snapshot from revision 37 (ubuntu-unity/next) -- Ubuntu daily release Wed, 08 May 2013 00:00:58 +0000 autopilot-gtk (1.3daily13.05.03ubuntu.unity.next-0ubuntu1) raring; urgency=low [ Christopher Lee ] * Bump version number [ Thomi Richards ] * property matching is broken (LP: #1175738) [ Christopher Lee , Thomi Richards ] * DBus wire protocol changes required (LP: #1155351) [ Alberto Mardegan ] * GtkTreeView's contents cannot be introspected (LP: #1160827) [ Ubuntu daily release ] * Automatic snapshot from revision 35 (ubuntu-unity/next) -- Ubuntu daily release Fri, 03 May 2013 00:00:55 +0000 autopilot-gtk (0.4daily13.03.11-0ubuntu1) raring; urgency=low [ Thomi Richards ] * Rebuild against libxpathselect1.2 [ Ubuntu daily release ] * Automatic snapshot from revision 31 -- Ubuntu daily release Mon, 11 Mar 2013 11:31:34 +0000 autopilot-gtk (0.4daily13.02.22-0ubuntu1) raring; urgency=low [ Thomi Richards ] * Need a log message to verify that the plugin loaded OK. (LP: #1130861) [ Automatic PS uploader ] * Automatic snapshot from revision 28 -- Automatic PS uploader Fri, 22 Feb 2013 00:01:29 +0000 autopilot-gtk (0.4daily13.02.14-0ubuntu1) raring; urgency=low * Automatic snapshot from revision 26 -- Automatic PS uploader Thu, 14 Feb 2013 00:01:51 +0000 autopilot-gtk (0.4daily13.02.08-0ubuntu1) raring; urgency=low [ Mathieu Trudel-Lapierre ] * Automatic snapshot from revision 1 (bootstrap). * debian/control: - Bump Build-Depends on debhelper to 9. - Update style: use trailing commas at the end of dep lists. - Update Vcs-Bzr, Vcs-Browser and add a notice to uploaders. - Adjust short, long descriptions for libautopilot-gtk packages. - Add Pre-Depends:; Multi-Arch: for libautopilot-gtk0 for multiarch. * debian/compat: bump to compat level 9. * debian/rules: - Override dh_install to remove *.la/*.a files and fail the build if there are files not being installed or missing from the build. - Override dh_makeshlibs to strictly check symbols. * debian/source/format: migrate back to source format 1.0. * debian/copyright: update format line. * debian/*.install: update paths for multiarch. [ Allan LeSage ] * debian/control: - Replace, Conflict, and Provide autopilot-gtk and libautopilot-gtk0. - Replace and Conflict libautopilot-gtk-dev. - Update Standards-Version to 3.9.4. - Remove '0' from libautopilot-gtk package. - Remove libautopilot-gtk-dev package, no longer needed. - Remove libindicate-dev from Build-Depends. * debian/libautopilot-gtk-dev.install: remove, no longer needed. * debian/libautopilot-gtk.install: remove, one-package install. * lib/CMakeLists.txt: - Remove SOVERSION. - Rename from autopilot-gtk to autopilot. - Install directly to gtk-3.0/modules. - Remove pc file to simplify. - Remove headers. * lib/autopilot-gtk.pc.in: remove to simplify. [ allanlesage@gmail.com, Allan LeSage ] * Hang in eog if no log_handler defined (?) (LP: #1111746) [ Automatic PS uploader ] * Automatic snapshot from revision 24 -- Automatic PS uploader Fri, 08 Feb 2013 16:34:17 +0000 autopilot-gtk (0.3-0ubuntu1) quantal; urgency=low * Fixed segfault on non-static name over gnome-calculator. -- Allan LeSage Fri, 19 Oct 2012 10:23:49 -0500 autopilot-gtk (0.2-0ubuntu1) quantal; urgency=low * Corrected packaging. -- Allan LeSage Thu, 18 Oct 2012 16:10:27 -0500 autopilot-gtk (0.1-0ubuntu1) quantal; urgency=low * Initial release -- Allan LeSage Wed, 15 Aug 2012 15:45:52 -0500 autopilot-gtk-1.6.0/lib/0000775000000000000000000000000013576175035011773 5ustar autopilot-gtk-1.6.0/lib/IntrospectionService.xml0000664000000000000000000000073313576175035016701 0ustar autopilot-gtk-1.6.0/lib/Introspection.cpp0000664000000000000000000001041113576175035015334 0ustar // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* * Copyright (C) 2012 Canonical Ltd * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Allan LeSage */ #include "Introspection.h" #include #include #include #include #include #include "GtkNode.h" #include "GtkRootNode.h" std::string AUTOPILOT_INTROSPECTION_OBJECT_PATH = "/com/canonical/Autopilot/Introspection"; void bus_acquired (GObject *object, GAsyncResult * res, gpointer user_data) { //g_debug("bus acquired"); GDBusConnection *bus; GError *error = NULL; bus = g_bus_get_finish (res, &error); if (!bus) { //g_warning ("unable to connect to the session bus: %s", error->message); g_error_free (error); return; } g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (autopilot_introspection), bus, AUTOPILOT_INTROSPECTION_OBJECT_PATH.c_str(), &error); if (error) { //g_warning ("unable to export autopilot introspection service on dbus: %s", error->message); g_error_free (error); return; } g_signal_connect (autopilot_introspection, "handle-get-state", G_CALLBACK(handle_get_state), NULL); g_signal_connect (autopilot_introspection, "handle-get-version", G_CALLBACK(handle_get_version), NULL); g_object_unref (bus); } gboolean handle_get_state (AutopilotIntrospection* introspection_service, GDBusMethodInvocation* invocation, const gchar * arg, gpointer user_data) { //g_debug("handling get-state method call"); GVariant* state; state = Introspect(arg); autopilot_introspection_complete_get_state(introspection_service, invocation, state); return TRUE; } gboolean handle_get_version (AutopilotIntrospection *introspection_service, GDBusMethodInvocation *invocation) { autopilot_introspection_complete_get_version(introspection_service, invocation, WIRE_PROTO_VERSION.c_str()); return TRUE; } GVariant* Introspect(std::string const& query_string) { //g_debug("introspecting our current GTK+ context"); GVariantBuilder* builder = g_variant_builder_new(G_VARIANT_TYPE("a(sv)")); std::list node_list = GetNodesThatMatchQuery(query_string); for (auto node: node_list) { std::string object_path = node->GetPath(); g_variant_builder_add(builder, "(sv)", object_path.c_str(), node->Introspect()); //g_debug("dumped object '%s'", object_path.c_str()); } GVariant* state = g_variant_new("a(sv)", builder); g_variant_builder_unref(builder); return state; } std::list GetNodesThatMatchQuery(std::string const& query_string) { //g_debug("getting nodes that match query"); std::shared_ptr root = std::make_shared(); //g_debug("selecting nodes"); std::list node_list; xpathselect::NodeVector selected_nodes_list; selected_nodes_list = xpathselect::SelectNodes(root, query_string); //g_debug("finished selecting nodes"); for (auto node : selected_nodes_list) { // node may be our root node wrapper *or* an ordinary GObject wrapper auto object_ptr = std::static_pointer_cast(node); if (object_ptr) node_list.push_back(object_ptr); } return node_list; } autopilot-gtk-1.6.0/lib/Variant.cpp0000664000000000000000000002001713576175035014103 0ustar // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* * Copyright (C) 2010 Canonical Ltd * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Tim Penhey */ #include #include #include "Variant.h" #include "autopilot_types.h" namespace variant { BuilderWrapper::BuilderWrapper(GVariantBuilder* builder) : builder_(builder) {} BuilderWrapper& BuilderWrapper::add(char const* name, bool value) { GVariantBuilder b; g_variant_builder_init(&b, G_VARIANT_TYPE("av")); g_variant_builder_add(&b, "v", g_variant_new_int32(TYPE_PLAIN)); g_variant_builder_add(&b, "v", g_variant_new_boolean(value)); g_variant_builder_add( builder_, "{sv}", name, g_variant_builder_end(&b) ); return *this; } BuilderWrapper& BuilderWrapper::add(char const* name, char const* value) { GVariantBuilder b; g_variant_builder_init(&b, G_VARIANT_TYPE("av")); g_variant_builder_add(&b, "v", g_variant_new_int32(TYPE_PLAIN)); if (value) g_variant_builder_add(&b, "v", g_variant_new_string(value)); else g_variant_builder_add(&b, "v", g_variant_new_string("")); g_variant_builder_add( builder_, "{sv}", name, g_variant_builder_end(&b) ); return *this; } BuilderWrapper& BuilderWrapper::add(char const* name, std::string const& value) { GVariantBuilder b; g_variant_builder_init(&b, G_VARIANT_TYPE("av")); g_variant_builder_add(&b, "v", g_variant_new_int32(TYPE_PLAIN)); g_variant_builder_add(&b, "v", g_variant_new_string(value.c_str())); g_variant_builder_add( builder_, "{sv}", name, g_variant_builder_end(&b) ); return *this; } BuilderWrapper& BuilderWrapper::add(char const* name, int value) { GVariantBuilder b; g_variant_builder_init(&b, G_VARIANT_TYPE("av")); g_variant_builder_add(&b, "v", g_variant_new_int32(TYPE_PLAIN)); g_variant_builder_add(&b, "v", g_variant_new_int32(value)); g_variant_builder_add( builder_, "{sv}", name, g_variant_builder_end(&b) ); return *this; } BuilderWrapper& BuilderWrapper::add(char const* name, long int value) { GVariantBuilder b; g_variant_builder_init(&b, G_VARIANT_TYPE("av")); g_variant_builder_add(&b, "v", g_variant_new_int32(TYPE_PLAIN)); g_variant_builder_add(&b, "v", g_variant_new_int64(value)); g_variant_builder_add( builder_, "{sv}", name, g_variant_builder_end(&b) ); return *this; } BuilderWrapper& BuilderWrapper::add(char const* name, long long int value) { GVariantBuilder b; g_variant_builder_init(&b, G_VARIANT_TYPE("av")); g_variant_builder_add(&b, "v", g_variant_new_int32(TYPE_PLAIN)); g_variant_builder_add(&b, "v", g_variant_new_int64(value)); g_variant_builder_add( builder_, "{sv}", name, g_variant_builder_end(&b) ); return *this; } BuilderWrapper& BuilderWrapper::add(char const* name, unsigned int value) { GVariantBuilder b; g_variant_builder_init(&b, G_VARIANT_TYPE("av")); g_variant_builder_add(&b, "v", g_variant_new_int32(TYPE_PLAIN)); g_variant_builder_add(&b, "v", g_variant_new_uint32(value)); g_variant_builder_add( builder_, "{sv}", name, g_variant_builder_end(&b) ); return *this; } BuilderWrapper& BuilderWrapper::add(char const* name, long unsigned int value) { GVariantBuilder b; g_variant_builder_init(&b, G_VARIANT_TYPE("av")); g_variant_builder_add(&b, "v", g_variant_new_int32(TYPE_PLAIN)); g_variant_builder_add(&b, "v", g_variant_new_uint64(value)); g_variant_builder_add( builder_, "{sv}", name, g_variant_builder_end(&b) ); return *this; } BuilderWrapper& BuilderWrapper::add(char const* name, long long unsigned int value) { GVariantBuilder b; g_variant_builder_init(&b, G_VARIANT_TYPE("av")); g_variant_builder_add(&b, "v", g_variant_new_int32(TYPE_PLAIN)); g_variant_builder_add(&b, "v", g_variant_new_uint64(value)); g_variant_builder_add( builder_, "{sv}", name, g_variant_builder_end(&b) ); return *this; } BuilderWrapper& BuilderWrapper::add(char const* name, float value) { GVariantBuilder b; g_variant_builder_init(&b, G_VARIANT_TYPE("av")); g_variant_builder_add(&b, "v", g_variant_new_int32(TYPE_PLAIN)); g_variant_builder_add(&b, "v", g_variant_new_double(value)); g_variant_builder_add( builder_, "{sv}", name, g_variant_builder_end(&b) ); return *this; } BuilderWrapper& BuilderWrapper::add(char const* name, double value) { GVariantBuilder b; g_variant_builder_init(&b, G_VARIANT_TYPE("av")); g_variant_builder_add(&b, "v", g_variant_new_int32(TYPE_PLAIN)); g_variant_builder_add(&b, "v", g_variant_new_double(value)); g_variant_builder_add( builder_, "{sv}", name, g_variant_builder_end(&b) ); return *this; } BuilderWrapper& BuilderWrapper::add(char const* name, GVariant* value) { if (value) { GVariantBuilder b; g_variant_builder_init(&b, G_VARIANT_TYPE("av")); g_variant_builder_add(&b, "v", g_variant_new_int32(TYPE_PLAIN)); g_variant_builder_add(&b, "v", value); g_variant_builder_add( builder_, "{sv}", name, g_variant_builder_end(&b) ); } return *this; } BuilderWrapper& BuilderWrapper::add_gvalue(char const* name, GValue* value) { switch (G_VALUE_TYPE(value)) { case G_TYPE_CHAR: { add(name, g_value_get_schar(value)); } break; case G_TYPE_UCHAR: { add(name, g_value_get_uchar(value)); } break; case G_TYPE_BOOLEAN: { add(name, (bool) g_value_get_boolean(value)); } break; case G_TYPE_INT: { add(name, g_value_get_int(value)); } break; case G_TYPE_UINT: { add(name, g_value_get_uint(value)); } break; case G_TYPE_LONG: { add(name, g_value_get_long(value)); } break; case G_TYPE_ULONG: { add(name, g_value_get_ulong(value)); } break; case G_TYPE_INT64: { add(name, g_value_get_int64(value)); } break; case G_TYPE_UINT64: { add(name, g_value_get_uint64(value)); } break; case G_TYPE_ENUM: { add(name, g_value_get_enum(value)); } break; case G_TYPE_FLAGS: { add(name, g_value_get_flags(value)); } break; case G_TYPE_FLOAT: { add(name, g_value_get_float(value)); } break; case G_TYPE_DOUBLE: { add(name, g_value_get_double(value)); } break; case G_TYPE_STRING: { add(name, g_value_get_string(value)); } break; case G_TYPE_POINTER: { add(name, g_value_get_pointer(value)); } break; case G_TYPE_BOXED: { add(name, g_value_get_boxed(value)); } break; case G_TYPE_PARAM: { add(name, g_value_get_param(value)); } break; case G_TYPE_OBJECT: { add(name, g_value_get_object(value)); } break; default: g_debug("unsupported type: %s", g_type_name(G_VALUE_TYPE(value))); {} break; } return *this; } BuilderWrapper& BuilderWrapper::BuilderWrapper::add(char const* name, GdkRectangle value) { GVariantBuilder b; g_variant_builder_init(&b, G_VARIANT_TYPE("av")); g_variant_builder_add(&b, "v", g_variant_new_int32(TYPE_RECT)); g_variant_builder_add(&b, "v", g_variant_new_int32(value.x)); g_variant_builder_add(&b, "v", g_variant_new_int32(value.y)); g_variant_builder_add(&b, "v", g_variant_new_int32(value.width)); g_variant_builder_add(&b, "v", g_variant_new_int32(value.height)); g_variant_builder_add( builder_, "{sv}", name, g_variant_builder_end(&b) ); return *this; } } autopilot-gtk-1.6.0/lib/GtkRootNode.h0000664000000000000000000000271013576175035014343 0ustar // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* * Copyright (C) 2012 Canonical Ltd * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Allan LeSage */ #ifndef ROOTGTKNODE_H #define ROOTGTKNODE_H #include "GtkNode.h" #include #include #include class GtkRootNode: public GtkNode { public: GtkRootNode(); virtual GVariant* Introspect() const; virtual std::string GetName() const; virtual std::string GetPath() const; virtual int32_t GetId() const; virtual bool MatchIntegerProperty(const std::string& name, int32_t value) const; virtual bool MatchBooleanProperty(const std::string& name, bool value) const; virtual bool MatchStringProperty(const std::string& name, const std::string& value) const; virtual xpathselect::NodeVector Children() const; private: virtual GVariant* GetChildNodeNames() const; }; #endif // ROOTGTKNODE_H autopilot-gtk-1.6.0/lib/autopilot_types.h0000664000000000000000000000210413576175035015405 0ustar /* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- * Copyright (C) 2013 Canonical Ltd * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #ifndef AUTOPILOT_TYPES_H #define AUTOPILOT_TYPES_H /// IMPORTANT: THese constants are taken from the autopilot XPathSelect protocol document. /// Only add options here if the support has been added for them in autopilot itself. enum autopilot_type_id { TYPE_PLAIN = 0, TYPE_RECT = 1, TYPE_POINT = 2, TYPE_SIZE = 3, TYPE_COLOR = 4, TYPE_DATETIME = 5, TYPE_TIME = 6, }; #endif autopilot-gtk-1.6.0/lib/main.h0000664000000000000000000000153113576175035013070 0ustar // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* * Copyright (C) 2012 Canonical Ltd * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Allan LeSage */ #ifndef MAIN_H #define MAIN_H extern "C" { int gtk_module_init(gint argc, char *argv[]); } #endif // MAIN_H autopilot-gtk-1.6.0/lib/CMakeLists.txt0000664000000000000000000000241713576175035014537 0ustar set(SOURCES main.cpp Variant.cpp GtkNode.cpp Introspection.cpp IntrospectionService.c GtkRootNode.cpp) set(HEADERS main.h GtkNode.h GtkRootNode.h Introspection.h IntrospectionService.h Variant.h) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -Wall -Werror -Wl,--no-undefined") add_library(autopilot SHARED ${SOURCES}) pkg_check_modules(GLIB REQUIRED glib-2.0) pkg_check_modules(GTK REQUIRED gtk+-3.0) pkg_check_modules(XPATHSELECT REQUIRED xpathselect) include_directories(${GLIB_INCLUDE_DIRS} ${GTK_INCLUDE_DIRS} ${XPATHSELECT_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR}) link_directories(${GLIB_LIBRARY_DIRS}) target_link_libraries(autopilot ${GLIB_LIBRARIES} ${GTK_LIBRARIES} ${XPATHSELECT_LIBRARIES}) add_custom_command( OUTPUT IntrospectionService.c IntrospectionService.h COMMAND gdbus-codegen ARGS --generate-c-code IntrospectionService --interface-prefix com.canonical ${CMAKE_CURRENT_SOURCE_DIR}/IntrospectionService.xml DEPENDS IntrospectionService.xml ) add_custom_target(generate_introspection_service DEPENDS IntrospectionService.xml) add_dependencies(autopilot generate_introspection_service) execute_process(COMMAND ln -s . lib/modules) install(TARGETS autopilot LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/gtk-3.0/modules) autopilot-gtk-1.6.0/lib/Variant.h0000664000000000000000000000350613576175035013554 0ustar // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* * Copyright (C) 2011 Canonical Ltd * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Tim Penhey */ #ifndef VARIANT_H #define VARIANT_H #include #include #include #include namespace variant { class BuilderWrapper { public: BuilderWrapper(GVariantBuilder* builder); BuilderWrapper& add(char const* name, bool value); BuilderWrapper& add(char const* name, char const* value); BuilderWrapper& add(char const* name, std::string const& value); BuilderWrapper& add(char const* name, int value); BuilderWrapper& add(char const* name, long int value); BuilderWrapper& add(char const* name, long long int value); BuilderWrapper& add(char const* name, unsigned int value); BuilderWrapper& add(char const* name, long unsigned int value); BuilderWrapper& add(char const* name, long long unsigned int value); BuilderWrapper& add(char const* name, float value); BuilderWrapper& add(char const* name, double value); BuilderWrapper& add(char const* name, GVariant* value); BuilderWrapper& add_gvalue(char const* name, GValue* value); BuilderWrapper& add(char const* name, GdkRectangle value); private: GVariantBuilder* builder_; }; } #endif // VARIANT_H autopilot-gtk-1.6.0/lib/GtkRootNode.cpp0000664000000000000000000000603113576175035014676 0ustar // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* * Copyright (C) 2012 Canonical Ltd * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Allan LeSage */ #include "GtkRootNode.h" #include #include #include #include #include "Variant.h" GtkRootNode::GtkRootNode() : GtkNode(NULL) { } GVariant* GtkRootNode::Introspect() const { GVariantBuilder builder; g_variant_builder_init(&builder, G_VARIANT_TYPE("a{sv}")); variant::BuilderWrapper builder_wrapper(&builder); // add our unique autopilot-id builder_wrapper.add(AP_ID_NAME.c_str(), GetId()); // add the names of our children builder_wrapper.add("Children", GetChildNodeNames()); return g_variant_builder_end(&builder); } int32_t GtkRootNode::GetId() const { return 1; } std::string GtkRootNode::GetName() const { return "Root"; } std::string GtkRootNode::GetPath() const { return "/" + GetName(); } bool GtkRootNode::MatchIntegerProperty(const std::string& name, int32_t value) const { // Root node only matches one property - id: if (name == "id") return value == GetId(); return false; } bool GtkRootNode::MatchBooleanProperty(const std::string& name, bool value) const { return false; } bool GtkRootNode::MatchStringProperty(const std::string& name, const std::string& value) const { return false; } xpathselect::NodeVector GtkRootNode::Children() const { //g_debug("getting the children of a node"); xpathselect::NodeVector children; // add all the toplevel nodes as children to the root node GList* toplevels_list = gtk_window_list_toplevels(); GList* elem; for (elem = toplevels_list; elem; elem = elem->next) { GObject *node = reinterpret_cast(elem->data); children.push_back(std::make_shared(node, shared_from_this())); // if the AtkObjects are available, expose the Atk hierarchy as well AtkObject *atk_object = gtk_widget_get_accessible(GTK_WIDGET(node)); if (atk_object != NULL) children.push_back(std::make_shared(G_OBJECT(atk_object), shared_from_this())); } g_list_free(toplevels_list); return children; } GVariant* GtkRootNode::GetChildNodeNames() const { //g_debug("getting the names of a node's children"); GVariantBuilder builder; g_variant_builder_init(&builder, G_VARIANT_TYPE_STRING_ARRAY); for (xpathselect::Node::Ptr child : Children()) { g_variant_builder_add(&builder, "s", child->GetName().c_str()); } return g_variant_builder_end(&builder); } autopilot-gtk-1.6.0/lib/GtkNode.cpp0000664000000000000000000003431413576175035014037 0ustar // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* * Copyright (C) 2012 Canonical Ltd * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Allan LeSage */ #include #include #include #include "GtkNode.h" #include "Variant.h" const std::string GtkNode::AP_ID_NAME = "id"; static guint32 cur_obj_id = 2; // start at 2 since 1 is reserved for the root node GtkNode::GtkNode(GObject* obj, GtkNode::Ptr const& parent) : object_(obj) , parent_(parent) { std::string parent_path = parent ? parent->GetPath() : ""; full_path_ = parent_path + "/" + GetName(); if (object_ != NULL) { g_object_ref(object_); GQuark OBJ_ID = g_quark_from_static_string("AUTOPILOT_OBJECT_ID"); gpointer val = g_object_get_qdata (object_, OBJ_ID); if (val == NULL) { g_object_set_qdata (object_, OBJ_ID, reinterpret_cast(cur_obj_id++)); } } } GtkNode::GtkNode(GObject* obj) : object_(obj) { full_path_ = "/" + GetName(); if (object_ != NULL) { g_object_ref(object_); GQuark OBJ_ID = g_quark_from_static_string("AUTOPILOT_OBJECT_ID"); gpointer val = g_object_get_qdata (object_, OBJ_ID); if (val == NULL) { g_object_set_qdata (object_, OBJ_ID, reinterpret_cast(cur_obj_id++)); } } } GtkNode::~GtkNode() { g_clear_object(&object_); } // we cannot represent GEnums, GFlags, etc. through D-BUS and autopilot's API, // so convert them to strings, ints, and other primitive types static void convert_value (GParamSpec *pspec, GValue *value) { if (G_VALUE_HOLDS_ENUM(value)) { GEnumValue *ev = g_enum_get_value(G_PARAM_SPEC_ENUM(pspec)->enum_class, g_value_get_enum(value)); if (ev != NULL) { //g_debug("attribute %s of type %s holds enum %s", g_param_spec_get_name(pspec), // g_type_name(pspec->value_type), ev->value_name); g_value_unset(value); *value = G_VALUE_INIT; g_value_init(value, G_TYPE_STRING); g_value_set_string(value, ev->value_name); } } // representing flags as strings is too unwieldy; let's just represent them // as integer if (G_VALUE_HOLDS_FLAGS(value)) { guint flags = g_value_get_flags(value); //g_debug("attribute %s of type %s holds flags %x", g_param_spec_get_name(pspec), // g_type_name(pspec->value_type), flags); g_value_unset(value); *value = G_VALUE_INIT; g_value_init(value, G_TYPE_UINT); g_value_set_uint(value, flags); } if (pspec->value_type == GTK_TYPE_TEXT_BUFFER) { GtkTextBuffer *buf = GTK_TEXT_BUFFER(g_value_get_object(value)); if (buf != NULL) { //g_debug("attribute %s of type %s holds GtkTextBuffer", g_param_spec_get_name(pspec), // g_type_name(pspec->value_type)); GtkTextIter start, end; gtk_text_buffer_get_start_iter(buf, &start); gtk_text_buffer_get_end_iter(buf, &end); gchar* text = gtk_text_iter_get_text(&start, &end); g_value_unset(value); *value = G_VALUE_INIT; g_value_init(value, G_TYPE_STRING); g_value_set_string(value, (text != NULL) ? text : ""); g_free(text); } } } GVariant* GtkNode::Introspect() const { GVariantBuilder builder; g_variant_builder_init(&builder, G_VARIANT_TYPE("a{sv}")); // add a GVariant of all our properties guint length; GParamSpec** properties = g_object_class_list_properties(G_OBJECT_GET_CLASS(object_), &length); variant::BuilderWrapper builder_wrapper(&builder); for (uint i = 0; i < length; ++i) { GParamSpec* param_spec = properties[i]; // ATK's accessible-table-* properties generate "invalid property id" warnings if (g_str_has_prefix(g_param_spec_get_name(param_spec), "accessible-table-")) continue; // see Launchpad bug #1108155: GtkTreePath mis-casts while copying, actuates here in "root" property if (g_strcmp0(g_type_name(param_spec->value_type), "GtkTreePath") != 0) { // some properties are only writeable; some toxic nodes change their names (?) if (param_spec->flags & G_PARAM_READABLE) { GValue value = G_VALUE_INIT; g_value_init(&value, param_spec->value_type); g_object_get_property(object_, g_param_spec_get_name(param_spec), &value); convert_value(param_spec, &value); builder_wrapper.add_gvalue(param_spec->name, &value); g_value_unset(&value); //Free the memory acquired by the value object. Absence of this was causig the applications to crash. } } else { //g_debug("skipped %s of type GtkTreePath", g_param_spec_get_name(param_spec)); } } g_free(properties); // add our unique autopilot-id builder_wrapper.add(AP_ID_NAME.c_str(), GetId()); // add the names of our children builder_wrapper.add("Children", GetChildNodeNames()); // add the GtkBuilder name if (GTK_IS_BUILDABLE (object_)) builder_wrapper.add("BuilderName", gtk_buildable_get_name(GTK_BUILDABLE (object_))); // add the GlobalRect property: "I am a GtkWidget" edition if (GTK_IS_WIDGET(object_)) { // FIXME: we'd like to remove this duplication (to GetGlobalRect) GtkWidget *widget = GTK_WIDGET (object_); GdkWindow *gdk_window = gtk_widget_get_window(widget); if (GDK_IS_WINDOW(gdk_window)) { GdkRectangle rect; GetGlobalRect(&rect); builder_wrapper.add("globalRect", rect); } } else if (ATK_IS_COMPONENT(object_)) { AddAtkComponentProperties(builder_wrapper, ATK_COMPONENT(object_)); } return g_variant_builder_end(&builder); } void GtkNode::AddAtkComponentProperties(variant::BuilderWrapper &builder_wrapper, AtkComponent *atk_component) const { AtkStateSet *states = atk_object_ref_state_set(ATK_OBJECT(atk_component)); /* Expose a few states which might be especially interesting for autopilot */ bool visible = atk_state_set_contains_state(states, ATK_STATE_VISIBLE); builder_wrapper.add("visible", visible); if (visible) { gint x, y, width, height; x = y = width = height = -1; atk_component_get_extents(atk_component, &x, &y, &width, &height, ATK_XY_SCREEN); GdkRectangle r; r.x = x; r.y = y; r.width = width; r.height = height; builder_wrapper.add("globalRect", r); } builder_wrapper.add("active", bool(atk_state_set_contains_state(states, ATK_STATE_ACTIVE))); builder_wrapper.add("checked", bool(atk_state_set_contains_state(states, ATK_STATE_CHECKED))); builder_wrapper.add("editable", bool(atk_state_set_contains_state(states, ATK_STATE_EDITABLE))); builder_wrapper.add("enabled", bool(atk_state_set_contains_state(states, ATK_STATE_ENABLED))); builder_wrapper.add("focused", bool(atk_state_set_contains_state(states, ATK_STATE_FOCUSED))); builder_wrapper.add("pressed", bool(atk_state_set_contains_state(states, ATK_STATE_PRESSED))); builder_wrapper.add("selected", bool(atk_state_set_contains_state(states, ATK_STATE_SELECTED))); builder_wrapper.add("sensitive", bool(atk_state_set_contains_state(states, ATK_STATE_SENSITIVE))); builder_wrapper.add("showing", bool(atk_state_set_contains_state(states, ATK_STATE_SHOWING))); g_object_unref(G_OBJECT(states)); } void GtkNode::GetGlobalRect(GdkRectangle* rect) const { GtkWidget *widget = GTK_WIDGET(object_); GdkWindow *gdk_window = gtk_widget_get_window(widget); GtkAllocation allocation; gint x, y; gtk_widget_get_allocation (widget, &allocation); gdk_window_get_root_coords(gdk_window, allocation.x, allocation.y, &x, &y); // if we wished to get the root root coords we might do this //gdk_window_get_root_coords(gdk_window, 0, 0, &x, &y); //g_debug ("root coords for widget %p(%s): %d %d (size %d %d)\n", widget, G_OBJECT_TYPE_NAME(widget), x, y, allocation.width, allocation.height); // FIXME: suck this up rect->x = x; rect->y = y; rect->width = allocation.width; rect->height = allocation.height; return; } std::string GtkNode::GetName() const { // autopilot uses the name of the GObject type if (!object_) { return std::string(); } return G_OBJECT_TYPE_NAME(object_); } std::string GtkNode::GetPath() const { return full_path_; } int32_t GtkNode::GetId() const { GQuark OBJ_ID = g_quark_from_static_string("AUTOPILOT_OBJECT_ID"); gpointer val = g_object_get_qdata (object_, OBJ_ID); // this uglyness is required in order to stop the compiler complaining about the fact // that we're casting a 64 bit type (gpointer) down to a 32 bit type (gint32) and may // be truncating the value. It's safe to do, however, since we control what values are // set in this quark, and they were initial gint32 values anyway. guint32 id = static_cast(reinterpret_cast(val)); return id; } xpathselect::Node::Ptr GtkNode::GetParent() const { return parent_; } bool GtkNode::MatchStringProperty(const std::string& name, const std::string& value) const { if (name == "BuilderName" && GTK_IS_BUILDABLE(object_)) { const gchar* builder_name = gtk_buildable_get_name(GTK_BUILDABLE (object_)); return builder_name != NULL && value.compare(builder_name) == 0; } GObjectClass* klass = G_OBJECT_GET_CLASS(object_); GParamSpec* pspec = g_object_class_find_property(klass, name.c_str()); if (pspec == NULL) return false; // read the property into a GValue g_debug("Matching property %s of type (%s).", g_param_spec_get_name(pspec), g_type_name(G_PARAM_SPEC_VALUE_TYPE(pspec))); GValue dest_value = G_VALUE_INIT; g_value_init(&dest_value, G_PARAM_SPEC_VALUE_TYPE(pspec)); g_object_get_property(object_, name.c_str(), &dest_value); convert_value(pspec, &dest_value); if (G_VALUE_TYPE(&dest_value) == G_TYPE_STRING) { const gchar *str = g_value_get_string(&dest_value); int result = g_strcmp0 (str, value.c_str()); g_value_unset(&dest_value); return result == 0; } else { g_debug("Property %s exists, but is not a string (is %s).", g_param_spec_get_name(pspec), g_type_name(G_VALUE_TYPE(&dest_value)) ); g_value_unset(&dest_value); return false; } } bool GtkNode::MatchIntegerProperty(const std::string& name, int32_t value) const { if (name == "id") return value == GetId(); GObjectClass* klass = G_OBJECT_GET_CLASS(object_); GParamSpec* pspec = g_object_class_find_property(klass, name.c_str()); if (pspec == NULL) return false; // read the property into a GValue g_debug("Matching property %s of type (%s).", g_param_spec_get_name(pspec), g_type_name(G_PARAM_SPEC_VALUE_TYPE(pspec))); GValue dest_value = G_VALUE_INIT; g_value_init(&dest_value, G_PARAM_SPEC_VALUE_TYPE(pspec)); g_object_get_property(object_, name.c_str(), &dest_value); convert_value(pspec, &dest_value); if (G_VALUE_TYPE(&dest_value) == G_TYPE_INT) { int v = g_value_get_int(&dest_value); g_value_unset(&dest_value); return value == v; } else if (G_VALUE_TYPE(&dest_value) == G_TYPE_UINT) { int v = g_value_get_uint(&dest_value); g_value_unset(&dest_value); return value == v; } else { g_debug("Property %s exists, but is not an integer (is %s).", g_param_spec_get_name(pspec), g_type_name(G_VALUE_TYPE(&dest_value)) ); g_value_unset(&dest_value); return false; } } bool GtkNode::MatchBooleanProperty(const std::string& name, bool value) const { GObjectClass* klass = G_OBJECT_GET_CLASS(object_); GParamSpec* pspec = g_object_class_find_property(klass, name.c_str()); if (pspec == NULL) return false; // read the property into a GValue g_debug("Matching property %s of type (%s).", g_param_spec_get_name(pspec), g_type_name(G_PARAM_SPEC_VALUE_TYPE(pspec))); GValue dest_value = G_VALUE_INIT; g_value_init(&dest_value, G_PARAM_SPEC_VALUE_TYPE(pspec)); g_object_get_property(object_, name.c_str(), &dest_value); convert_value(pspec, &dest_value); if (G_VALUE_TYPE(&dest_value) == G_TYPE_BOOLEAN) { bool v = g_value_get_boolean(&dest_value); g_value_unset(&dest_value); return value == v; } else { g_debug("Property %s exists, but is not a boolean (is %s).", g_param_spec_get_name(pspec), g_type_name(G_VALUE_TYPE(&dest_value)) ); g_value_unset(&dest_value); return false; } } xpathselect::NodeVector GtkNode::Children() const { //g_debug("getting the children of a node"); xpathselect::NodeVector children; if (GTK_IS_CONTAINER(object_)) { GList* gtk_children = gtk_container_get_children(GTK_CONTAINER(object_)); for (GList* elem = gtk_children; elem; elem = elem->next) { children.push_back(std::make_shared(G_OBJECT(elem->data), shared_from_this())); } g_list_free(gtk_children); } else if (ATK_IS_OBJECT(object_)) { AtkObject *atk_object = ATK_OBJECT(object_); int n_children = atk_object_get_n_accessible_children(atk_object); for (int i = 0; i < n_children; i++) { AtkObject *child = atk_object_ref_accessible_child(atk_object, i); children.push_back(std::make_shared(G_OBJECT(child), shared_from_this())); } } return children; } GVariant* GtkNode::GetChildNodeNames() const { //g_debug("getting the names of a node's children"); GVariantBuilder builder; g_variant_builder_init(&builder, G_VARIANT_TYPE_STRING_ARRAY); for (xpathselect::Node::Ptr child : Children()) { g_variant_builder_add(&builder, "s", child->GetName().c_str()); } return g_variant_builder_end(&builder); } autopilot-gtk-1.6.0/lib/main.cpp0000664000000000000000000000604113576175035013424 0ustar // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* * Copyright (C) 2012 Canonical Ltd * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Allan LeSage */ #include #include #include #include #include #include "main.h" #include "Introspection.h" #include "IntrospectionService.h" namespace { std::string filename; GLogLevelFlags levels_to_log; std::ostream& get_log_stream() { if (!filename.empty()) { static std::ofstream fstream(filename); return fstream; } else { return std::cout; } } std::string get_level_name(GLogLevelFlags lvl) { switch(lvl) { case G_LOG_LEVEL_DEBUG: return "DEBUG"; case G_LOG_LEVEL_INFO: return "INFO"; case G_LOG_LEVEL_MESSAGE: return "MESSAGE"; case G_LOG_LEVEL_WARNING: return "WARNING"; case G_LOG_LEVEL_CRITICAL: return "CRITICAL"; case G_LOG_LEVEL_ERROR: return "ERROR"; default: return "UNKNOWN"; } } } AutopilotIntrospection* autopilot_introspection = NULL; void LogHandler (const gchar* log_domain, GLogLevelFlags log_level, const gchar* message, gpointer user_data) { if (log_level & levels_to_log) { std::string domain = log_domain ? log_domain : "default"; get_log_stream() << "[" << domain << "] " << get_level_name(log_level) << ": " << message << std::endl; } } void initialise_logging() { if (getenv("AP_GTK_LOG_VERBOSE")) { levels_to_log = (GLogLevelFlags) ( G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION); } else { levels_to_log = (GLogLevelFlags)( G_LOG_LEVEL_WARNING | G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION); } char* fname = getenv("AP_GTK_LOG_FILE"); if (fname && strcmp(fname, "") != 0) { filename = fname; } g_log_set_default_handler(LogHandler, NULL); } int gtk_module_init(gint argc, char *argv[]) { initialise_logging(); autopilot_introspection = autopilot_introspection_skeleton_new (); g_bus_get (G_BUS_TYPE_SESSION, NULL, bus_acquired, NULL); // always log this: std::cout << "Autopilot GTK interface loaded. Wire protocol version is " << WIRE_PROTO_VERSION << "." << std::endl; return 0; } int display_init_func(GdkDisplay* display) { // FIXME: module fails to load if this is not defined, but is it necessary? return 0; } autopilot-gtk-1.6.0/lib/Introspection.h0000664000000000000000000000316513576175035015011 0ustar // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* * Copyright (C) 2012 Canonical Ltd * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Allan LeSage */ #ifndef INTROSPECTION_H #define INTROSPECTION_H #include #include #include "GtkNode.h" #include "IntrospectionService.h" extern AutopilotIntrospection* autopilot_introspection; static std::string WIRE_PROTO_VERSION("1.4"); void bus_acquired (GObject *object, GAsyncResult * res, gpointer user_data); gboolean handle_get_state (AutopilotIntrospection* introspection_service, GDBusMethodInvocation* invocation, const gchar * arg, gpointer user_data); gboolean handle_get_version (AutopilotIntrospection *introspection_service, GDBusMethodInvocation *invocation); GVariant* Introspect(std::string const& query_string); std::list GetNodesThatMatchQuery(std::string const& query_string); #endif // INTROSPECTION_H autopilot-gtk-1.6.0/lib/GtkNode.h0000664000000000000000000000425513576175035013505 0ustar // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* * Copyright (C) 2012 Canonical Ltd * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Allan LeSage */ #ifndef GTKNODE_H #define GTKNODE_H #include #include #include #include #include #include #include "Variant.h" // #include class GtkNode: public xpathselect::Node, public std::enable_shared_from_this { public: typedef std::shared_ptr Ptr; GtkNode(GObject* object, Ptr const& parent); GtkNode(GObject* object); virtual ~GtkNode(); virtual GVariant* Introspect() const; virtual std::string GetName() const; virtual std::string GetPath() const; virtual int32_t GetId() const; virtual xpathselect::Node::Ptr GetParent() const; virtual bool MatchStringProperty(const std::string& name, const std::string& value) const; virtual bool MatchIntegerProperty(const std::string& name, int32_t value) const; virtual bool MatchBooleanProperty(const std::string& name, bool value) const; virtual xpathselect::NodeVector Children() const; static const std::string AP_ID_NAME; private: GObject *object_; std::string full_path_; Ptr parent_; virtual GVariant* GetChildNodeNames() const; virtual void GetGlobalRect(GdkRectangle* rect) const; void AddAtkComponentProperties(variant::BuilderWrapper &builder_wrapper, AtkComponent *atk_component) const; }; #endif // GTKNODE_H