gtk-stream 0.6.1__tar.gz → 0.7.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. {gtk_stream-0.6.1 → gtk_stream-0.7.1}/PKG-INFO +1 -1
  2. {gtk_stream-0.6.1 → gtk_stream-0.7.1}/gtk_stream/application.py +3 -2
  3. {gtk_stream-0.6.1 → gtk_stream-0.7.1}/gtk_stream/command_line.py +20 -4
  4. {gtk_stream-0.6.1 → gtk_stream-0.7.1}/gtk_stream/common.py +30 -2
  5. {gtk_stream-0.6.1 → gtk_stream-0.7.1}/gtk_stream/documents/__init__.py +1 -0
  6. {gtk_stream-0.6.1 → gtk_stream-0.7.1}/gtk_stream/documents/classes/Button.py +2 -2
  7. {gtk_stream-0.6.1 → gtk_stream-0.7.1}/gtk_stream/documents/classes/Document.py +3 -2
  8. {gtk_stream-0.6.1 → gtk_stream-0.7.1}/gtk_stream/documents/classes/Dropdown.py +1 -1
  9. gtk_stream-0.7.1/gtk_stream/documents/classes/FlowBox.py +34 -0
  10. {gtk_stream-0.6.1 → gtk_stream-0.7.1}/gtk_stream/documents/classes/Switch.py +1 -1
  11. {gtk_stream-0.6.1 → gtk_stream-0.7.1}/gtk_stream/parser.py +22 -8
  12. {gtk_stream-0.6.1 → gtk_stream-0.7.1}/gtk_stream.egg-info/PKG-INFO +1 -1
  13. {gtk_stream-0.6.1 → gtk_stream-0.7.1}/gtk_stream.egg-info/SOURCES.txt +1 -0
  14. {gtk_stream-0.6.1 → gtk_stream-0.7.1}/pyproject.toml +1 -1
  15. {gtk_stream-0.6.1 → gtk_stream-0.7.1}/README.md +0 -0
  16. {gtk_stream-0.6.1 → gtk_stream-0.7.1}/gtk_stream/__init__.py +0 -0
  17. {gtk_stream-0.6.1 → gtk_stream-0.7.1}/gtk_stream/documents/classes/Box.py +0 -0
  18. {gtk_stream-0.6.1 → gtk_stream-0.7.1}/gtk_stream/documents/classes/Frame.py +0 -0
  19. {gtk_stream-0.6.1 → gtk_stream-0.7.1}/gtk_stream/documents/classes/Grid.py +0 -0
  20. {gtk_stream-0.6.1 → gtk_stream-0.7.1}/gtk_stream/documents/classes/Label.py +0 -0
  21. {gtk_stream-0.6.1 → gtk_stream-0.7.1}/gtk_stream/documents/classes/Paned.py +0 -0
  22. {gtk_stream-0.6.1 → gtk_stream-0.7.1}/gtk_stream/documents/classes/Picture.py +0 -0
  23. {gtk_stream-0.6.1 → gtk_stream-0.7.1}/gtk_stream/documents/classes/ProgressBar.py +0 -0
  24. {gtk_stream-0.6.1 → gtk_stream-0.7.1}/gtk_stream/documents/classes/ScrolledWindow.py +0 -0
  25. {gtk_stream-0.6.1 → gtk_stream-0.7.1}/gtk_stream/documents/classes/Separator.py +0 -0
  26. {gtk_stream-0.6.1 → gtk_stream-0.7.1}/gtk_stream/documents/classes/Stack.py +0 -0
  27. {gtk_stream-0.6.1 → gtk_stream-0.7.1}/gtk_stream/documents/classes/__init__.py +0 -0
  28. {gtk_stream-0.6.1 → gtk_stream-0.7.1}/gtk_stream/properties.py +0 -0
  29. {gtk_stream-0.6.1 → gtk_stream-0.7.1}/gtk_stream.egg-info/dependency_links.txt +0 -0
  30. {gtk_stream-0.6.1 → gtk_stream-0.7.1}/gtk_stream.egg-info/entry_points.txt +0 -0
  31. {gtk_stream-0.6.1 → gtk_stream-0.7.1}/gtk_stream.egg-info/requires.txt +0 -0
  32. {gtk_stream-0.6.1 → gtk_stream-0.7.1}/gtk_stream.egg-info/top_level.txt +0 -0
  33. {gtk_stream-0.6.1 → gtk_stream-0.7.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: gtk-stream
3
- Version: 0.6.1
3
+ Version: 0.7.1
4
4
  Summary: A simple stream-oriented GUI protocol
5
5
  Author-email: Marc Coiffier <marc.coiffier@univ-grenoble-alpes.fr>
6
6
  Project-URL: Homepage, https://coiffier.net/projects/gtk-stream/
@@ -20,8 +20,9 @@ from .common import printEvent
20
20
  from .properties import parse_property, get_prop_type
21
21
 
22
22
  class GtkStreamApp(Gtk.Application):
23
- def __init__(self, name = None, **kwargs):
23
+ def __init__(self, logger, name = None, **kwargs):
24
24
  super().__init__(**kwargs)
25
+ self.logger = logger
25
26
  if name != None:
26
27
  GLib.set_application_name(name)
27
28
  self.namedWidgets = { }
@@ -66,7 +67,7 @@ class GtkStreamApp(Gtk.Application):
66
67
  win.set_default_size(int(width), int(height))
67
68
  self.namedWindows[id] = win
68
69
  win.set_child(document.render())
69
- win.connect('close-request', printEvent('close-request', id))
70
+ win.connect('close-request', printEvent(self.logger, 'close-request', id))
70
71
  win.present()
71
72
  return False
72
73
  self.run_when_idle(cb)
@@ -16,15 +16,31 @@
16
16
 
17
17
  import io
18
18
  import xml.sax as sax
19
- import signal
19
+ import sys
20
+ import os
20
21
 
21
22
  from .parser import GtkStreamXMLHandler
23
+ from .common import Logger, LogLevel
24
+ from . import GLib
25
+
26
+ logLevel = LogLevel.__dict__.get(os.environ.get('GTK_STREAM_LOGLEVEL', 'WARN'), LogLevel.WARN)
27
+
28
+ logger = Logger(logLevel)
29
+
30
+ class GtkStreamErrorHandler(sax.handler.ErrorHandler):
31
+ def error(self, exc):
32
+ raise exc
33
+ def fatalError(self, exc):
34
+ raise exc
22
35
 
23
36
  def main():
24
- handler = GtkStreamXMLHandler()
37
+ handler = GtkStreamXMLHandler(logger)
38
+ errHandler = GtkStreamErrorHandler()
25
39
  parser = sax.make_parser()
26
40
  parser.setContentHandler(handler)
41
+ parser.setErrorHandler(errHandler)
27
42
  try:
28
43
  parser.parse(io.FileIO(0, 'r', closefd=False))
29
- finally:
30
- handler.app.release()
44
+ except Exception as e:
45
+ logger.error("Done with exception : %s", e)
46
+ handler.quit_application()
@@ -15,6 +15,7 @@
15
15
  # along with this program. If not, see <https://www.gnu.org/licenses/>.
16
16
 
17
17
  import sys
18
+ from enum import Enum
18
19
 
19
20
  def _data_str_default(*args):
20
21
  return ''
@@ -23,13 +24,40 @@ def _data_str_by(get_data):
23
24
  return ":"+get_data(*args)
24
25
  return ret
25
26
 
26
- def printEvent(event, id, retval = None, get_data = None):
27
+ def printEvent(logger, event, id, retval = None, get_data = None):
27
28
  data_str = _data_str_default if get_data == None else _data_str_by(get_data)
28
29
  def ret(*args):
29
30
  try:
30
31
  print("{}:{}{}".format(id,event,data_str(*args)), file=sys.stdout)
31
32
  sys.stdout.flush()
32
33
  except Exception as e:
33
- print("Exception when writing an event: {}".format(e), file=sys.stderr)
34
+ logger.error("Exception when writing an event: %s", e)
34
35
  return retval
35
36
  return ret
37
+
38
+ class LogLevel(Enum):
39
+ DEBUG = 0
40
+ INFO = 1
41
+ WARN = 2
42
+ ERROR = 3
43
+
44
+ class Logger:
45
+ def __init__(self, level = LogLevel.WARN, stderr = sys.stderr):
46
+ self.stderr = stderr
47
+ self.level = level
48
+ self.debug = self._initLogger(LogLevel.DEBUG)
49
+ self.info = self._initLogger(LogLevel.INFO)
50
+ self.warn = self._initLogger(LogLevel.WARN)
51
+ self.error = self._initLogger(LogLevel.ERROR)
52
+ def flush(self):
53
+ self.stderr.flush()
54
+
55
+ def _initLogger(self, level):
56
+ if self.level.value <= level.value:
57
+ def ret(fmt, *args):
58
+ print((f"[{level.name}]: {fmt}") % args, file=self.stderr)
59
+ return ret
60
+ else:
61
+ def ret(*args):
62
+ pass
63
+ return ret
@@ -10,6 +10,7 @@ from .classes.Dropdown import Dropdown, Item
10
10
  from .classes.Switch import Switch
11
11
 
12
12
  from .classes.Box import Box, BoxPrepend
13
+ from .classes.FlowBox import FlowBox, FlowBoxPrepend
13
14
  from .classes.ScrolledWindow import ScrolledWindow
14
15
  from .classes.Paned import Paned
15
16
  from .classes.Frame import Frame, FrameLabel
@@ -24,7 +24,7 @@ class Button(Document):
24
24
  super().__init__(app, id = id, **kwargs)
25
25
  def render_raw(self):
26
26
  button = Gtk.Button()
27
- button.connect('clicked', printEvent('clicked', self.id))
27
+ button.connect('clicked', printEvent(self.app.logger, 'clicked', self.id))
28
28
  return button
29
29
  def insert_child(self, w, d):
30
30
  w.set_child(d.render())
@@ -35,7 +35,7 @@ class LinkButton(Button):
35
35
  super().__init__(app, id=id, **kwargs)
36
36
  def render_raw(self):
37
37
  button = Gtk.LinkButton()
38
- button.connect('activate-link', printEvent('clicked', self.id, True))
38
+ button.connect('activate-link', printEvent(self.app.logger, 'clicked', self.id, True))
39
39
  return button
40
40
  def insert_child(self, w, d):
41
41
  w.set_child(d.render())
@@ -33,8 +33,9 @@ class Document:
33
33
  def set_properties(self, w):
34
34
  self.app.nameWidget(self.id, w)
35
35
  for (p,v) in self.props.items():
36
- # print(f"Setting property '{p}' to '{v}' in widget {self.__class__}", file=sys.stderr)
37
- w.set_property(p, v(self.app))
36
+ val = v(self.app)
37
+ self.app.logger.debug("Setting property '%s' to '%s' in widget %s", p, val, self.__class__)
38
+ w.set_property(p, val)
38
39
  w.insert_child = lambda d: self.insert_child(w, d)
39
40
  def render(self):
40
41
  w = self.render_raw()
@@ -59,7 +59,7 @@ class Dropdown(Document):
59
59
 
60
60
  ret = Gtk.DropDown(model=model, expression=Gtk.PropertyExpression.new(_ItemObject, None, 'item_value'), factory=factory)
61
61
 
62
- ret.connect('notify::selected-item', printEvent('selected', self.id, get_data = lambda w,_: w.get_selected_item().value))
62
+ ret.connect('notify::selected-item', printEvent(self.app.logger, 'selected', self.id, get_data = lambda w,_: w.get_selected_item().value))
63
63
  return ret
64
64
  def insert_child(self, w, d):
65
65
  pass
@@ -0,0 +1,34 @@
1
+ # Gtk-Stream : A stream-based GUI protocol
2
+ # Copyright (C) 2024 Marc Coiffier
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <https://www.gnu.org/licenses/>.
16
+
17
+ from ... import Gtk
18
+ from .. import Document, PseudoDocument
19
+
20
+ class FlowBoxPrepend(PseudoDocument):
21
+ def __init__(self, app):
22
+ super().__init__(app)
23
+
24
+ class FlowBox(Document):
25
+ __g_class__ = Gtk.FlowBox
26
+ def __init__(self, app, **kwargs):
27
+ super().__init__(app, **kwargs)
28
+ def render_raw(self):
29
+ return Gtk.FlowBox()
30
+ def insert_child(self, w, d):
31
+ if isinstance(d, FlowBoxPrepend):
32
+ w.prepend(d.render())
33
+ else:
34
+ w.append(d.render())
@@ -26,7 +26,7 @@ class Switch(Document):
26
26
  self.managed = parse_property('gboolean', managed)(app)
27
27
  def render_raw(self):
28
28
  ret = Gtk.Switch()
29
- ret.connect('state-set', printEvent('switch', self.id,
29
+ ret.connect('state-set', printEvent(self.app.logger, 'switch', self.id,
30
30
  retval = self.managed,
31
31
  get_data = lambda _,state: "on" if state else "off"))
32
32
  return ret
@@ -45,17 +45,30 @@ WIDGET_DOCUMENTS = {
45
45
  'picture' : docs.Picture,
46
46
  'separator' : docs.Separator,
47
47
  'scrolled-window' : docs.ScrolledWindow,
48
- 'stack' : docs.Stack
48
+ 'stack' : docs.Stack,
49
+ 'flow-box' : docs.FlowBox,
50
+ 'flow-box-prepend': docs.FlowBoxPrepend
49
51
  }
50
52
 
51
53
  class GtkStreamXMLHandler(sax.ContentHandler):
52
- def __init__(self):
54
+ def __init__(self, logger):
55
+ self.logger = logger
53
56
  self.transition_enter = self.transE_conn
54
57
  self.transition_leave = self.transL_final
55
58
  self.transition_chars = self.ignore_chars
56
59
  self.namedWidgets = { }
57
60
  self.windows = { }
58
61
 
62
+ def quit_application(self):
63
+ def cb():
64
+ self.logger.info("Quitting app")
65
+ self.app.quit()
66
+ GLib.idle_add(cb)
67
+ self.logger.info("Waiting for app to terminate")
68
+ self.app_thread.join()
69
+ self.logger.info("App terminated")
70
+ sys.exit(0)
71
+
59
72
  def setNamed(self, attrs, ):
60
73
  if 'id' in attrs:
61
74
  self.namedWidgets[attrs['id']] = widget
@@ -80,19 +93,20 @@ class GtkStreamXMLHandler(sax.ContentHandler):
80
93
  def transE_conn(self, name, attrs):
81
94
  match name:
82
95
  case 'application':
83
- self.app = GtkStreamApp(**attrs)
96
+ self.app = GtkStreamApp(self.logger, **attrs)
84
97
  def on_activate(a):
85
98
  a.hold()
86
99
  self.app.connect('activate', on_activate)
87
100
  def appMain():
88
101
  self.app.run([])
89
- threading.Thread(target = appMain).start()
102
+ self.app_thread = threading.Thread(target = appMain)
103
+ self.app_thread.start()
104
+
90
105
  def on_sigint(a,b):
91
- def cb():
92
- self.app.quit()
93
- sys.exit(0)
94
- GLib.idle_add(cb)
106
+ self.logger.info("SIGINT received")
107
+ self.quit_application()
95
108
  signal.signal(signal.SIGINT, on_sigint)
109
+
96
110
  self.transition_enter = self.transE_message
97
111
  self.transition_leave = self.transL_tag('application', self.transE_final, self.transL_final)
98
112
  case _:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: gtk-stream
3
- Version: 0.6.1
3
+ Version: 0.7.1
4
4
  Summary: A simple stream-oriented GUI protocol
5
5
  Author-email: Marc Coiffier <marc.coiffier@univ-grenoble-alpes.fr>
6
6
  Project-URL: Homepage, https://coiffier.net/projects/gtk-stream/
@@ -17,6 +17,7 @@ gtk_stream/documents/classes/Box.py
17
17
  gtk_stream/documents/classes/Button.py
18
18
  gtk_stream/documents/classes/Document.py
19
19
  gtk_stream/documents/classes/Dropdown.py
20
+ gtk_stream/documents/classes/FlowBox.py
20
21
  gtk_stream/documents/classes/Frame.py
21
22
  gtk_stream/documents/classes/Grid.py
22
23
  gtk_stream/documents/classes/Label.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "gtk-stream"
7
- version = "0.6.1"
7
+ version = "0.7.1"
8
8
  description = "A simple stream-oriented GUI protocol"
9
9
  authors = [
10
10
  { name = "Marc Coiffier", email = "marc.coiffier@univ-grenoble-alpes.fr" }
File without changes
File without changes