Hi I am trying to create a program that when run, two windows open at the same time, from the same app. For this multihtreading is needed, but it seems I get some strange errors:
XIO: fatal IO error 0 (Success) on X server ":0"
after 187 requests (187 known processed) with 24 events remaining.
[xcb] Unknown sequence number while processing queue
[xcb] You called XInitThreads, this is not your fault
[xcb] Aborting, sorry about that.
python: xcb_io.c:278: poll_for_event: Assertion `!xcb_xlib_threads_sequence_lost' failed.
for now this is just a test implementation, copying two of the same windows, for simplicity. In the future two different windows' for different purposes will be done.
I will send my full code I am working with because strangely, a simpler version with same exact structure works:
from multiprocessing import Process
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
KV = '''
BoxLayout:
orientation: 'vertical'
Label:
text: "This is a window"
'''
class MainApp(App):
def build(self):
return Builder.load_string(KV)
def run_app():
MainApp().run()
if __name__ == '__main__':
processes = [Process(target=run_app) for _ in range(2)]
for p in processes:
p.start()
for p in processes:
p.join()
my code now:
from kivymd.app import MDApp
from kivymd.uix.screen import MDScreen
from kivymd.uix.card import MDCard
from kivymd.uix.label import MDLabel
from kivymd.uix.button import MDButton, MDIconButton
from kivymd.uix.relativelayout import MDRelativeLayout
from kivymd.uix.boxlayout import MDBoxLayout
from multiprocessing import Process
class OrderCard(MDCard):
_card_count = 0
def __init__(self, **kwargs):
OrderCard._card_count += 1
super().__init__(
padding="8dp",
size_hint=(1, None),
height="100dp",
**kwargs
)
layout = MDRelativeLayout()
label = MDLabel(
text=f"Order Added {OrderCard._card_count}",
adaptive_size=True,
text_color="grey",
pos_hint={"center_y": 0.5, "center_x": 0.5},
bold=True
)
layout.add_widget(label)
buttons_layout = MDBoxLayout(
orientation='horizontal',
size_hint=(None, None),
width="96dp",
height="48dp",
pos_hint={"top": 1, "right": 1},
spacing="4dp"
)
edit_btn = MDIconButton(
icon="square-edit-outline",
on_press=self.edit_card,
size=("24dp", "24dp")
)
delete_btn = MDIconButton(
icon="trash-can-outline",
on_press=self.delete_card,
size=("24dp", "24dp")
)
buttons_layout.add_widget(edit_btn)
buttons_layout.add_widget(delete_btn)
layout.add_widget(buttons_layout)
self.add_widget(layout)
def delete_card(self, *args):
parent = self.parent
parent.remove_widget(self)
def edit_card(self, *args):
print("Entered menu")
class MainScreen(MDScreen):
def add_order(self):
stack = self.ids.stack
stack.add_widget(OrderCard(size_hint_y=None))
class MainApp(MDApp):
def build(self):
self.theme_cls.theme_style = "Light"
self.theme_cls.primary_palette = "Moccasin"
return MainScreen()
def run_app():
MainApp().run()
if __name__ == '__main__':
processes = [Process(target=run_app) for _ in range(2)]
for p in processes:
p.start()
for p in processes:
p.join()
main.kv:
<MainScreen>:
md_bg_color: self.theme_cls.backgroundColor
BoxLayout:
padding: "10sp"
ScrollView:
do_scroll_x: False
do_scroll_y: True
StackLayout:
on_children:
if self.parent.scroll_y == 0.0: self.parent.scroll_y = 0.00000001
size_hint_y: None
height: self.minimum_height
spacing: "15sp"
padding: "20sp"
id: stack
BoxLayout:
orientation: 'vertical'
padding: "20sp"
width: "160dp"
size_hint_x: None
MDButton:
spacing: "10sp"
style: "elevated"
size: "100sp", "70sp"
size_hint: None,None
on_release: root.add_order()
MDButtonIcon:
icon: "plus"
MDButtonText:
id: order_btn
text: "Add Order"
theme_font_size: "Custom"
font_size: "15sp"
Widget:
Tried removing anything related to KivyMD library and use pure Kivy instead, but with no success. Expected seeing two windows launch at the same time when the python program is run.
Hi I am trying to create a program that when run, two windows open at the same time, from the same app. For this multihtreading is needed, but it seems I get some strange errors:
XIO: fatal IO error 0 (Success) on X server ":0"
after 187 requests (187 known processed) with 24 events remaining.
[xcb] Unknown sequence number while processing queue
[xcb] You called XInitThreads, this is not your fault
[xcb] Aborting, sorry about that.
python: xcb_io.c:278: poll_for_event: Assertion `!xcb_xlib_threads_sequence_lost' failed.
for now this is just a test implementation, copying two of the same windows, for simplicity. In the future two different windows' for different purposes will be done.
I will send my full code I am working with because strangely, a simpler version with same exact structure works:
from multiprocessing import Process
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
KV = '''
BoxLayout:
orientation: 'vertical'
Label:
text: "This is a window"
'''
class MainApp(App):
def build(self):
return Builder.load_string(KV)
def run_app():
MainApp().run()
if __name__ == '__main__':
processes = [Process(target=run_app) for _ in range(2)]
for p in processes:
p.start()
for p in processes:
p.join()
my code now:
from kivymd.app import MDApp
from kivymd.uix.screen import MDScreen
from kivymd.uix.card import MDCard
from kivymd.uix.label import MDLabel
from kivymd.uix.button import MDButton, MDIconButton
from kivymd.uix.relativelayout import MDRelativeLayout
from kivymd.uix.boxlayout import MDBoxLayout
from multiprocessing import Process
class OrderCard(MDCard):
_card_count = 0
def __init__(self, **kwargs):
OrderCard._card_count += 1
super().__init__(
padding="8dp",
size_hint=(1, None),
height="100dp",
**kwargs
)
layout = MDRelativeLayout()
label = MDLabel(
text=f"Order Added {OrderCard._card_count}",
adaptive_size=True,
text_color="grey",
pos_hint={"center_y": 0.5, "center_x": 0.5},
bold=True
)
layout.add_widget(label)
buttons_layout = MDBoxLayout(
orientation='horizontal',
size_hint=(None, None),
width="96dp",
height="48dp",
pos_hint={"top": 1, "right": 1},
spacing="4dp"
)
edit_btn = MDIconButton(
icon="square-edit-outline",
on_press=self.edit_card,
size=("24dp", "24dp")
)
delete_btn = MDIconButton(
icon="trash-can-outline",
on_press=self.delete_card,
size=("24dp", "24dp")
)
buttons_layout.add_widget(edit_btn)
buttons_layout.add_widget(delete_btn)
layout.add_widget(buttons_layout)
self.add_widget(layout)
def delete_card(self, *args):
parent = self.parent
parent.remove_widget(self)
def edit_card(self, *args):
print("Entered menu")
class MainScreen(MDScreen):
def add_order(self):
stack = self.ids.stack
stack.add_widget(OrderCard(size_hint_y=None))
class MainApp(MDApp):
def build(self):
self.theme_cls.theme_style = "Light"
self.theme_cls.primary_palette = "Moccasin"
return MainScreen()
def run_app():
MainApp().run()
if __name__ == '__main__':
processes = [Process(target=run_app) for _ in range(2)]
for p in processes:
p.start()
for p in processes:
p.join()
main.kv:
<MainScreen>:
md_bg_color: self.theme_cls.backgroundColor
BoxLayout:
padding: "10sp"
ScrollView:
do_scroll_x: False
do_scroll_y: True
StackLayout:
on_children:
if self.parent.scroll_y == 0.0: self.parent.scroll_y = 0.00000001
size_hint_y: None
height: self.minimum_height
spacing: "15sp"
padding: "20sp"
id: stack
BoxLayout:
orientation: 'vertical'
padding: "20sp"
width: "160dp"
size_hint_x: None
MDButton:
spacing: "10sp"
style: "elevated"
size: "100sp", "70sp"
size_hint: None,None
on_release: root.add_order()
MDButtonIcon:
icon: "plus"
MDButtonText:
id: order_btn
text: "Add Order"
theme_font_size: "Custom"
font_size: "15sp"
Widget:
Tried removing anything related to KivyMD library and use pure Kivy instead, but with no success. Expected seeing two windows launch at the same time when the python program is run.
Share Improve this question asked yesterday George RăbușGeorge Răbuș 32 bronze badges New contributor George Răbuș is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct. 01 Answer
Reset to default 0I am not sure exactly why your approach does not work. However, keep in mind that when using multiprocessing, your code may get loaded several times by the initial process. That may lead to issues, including multiple executions of some of your code. Those issues are difficult to diagnose, since the Process
class doesn't provide any convenient way to access stderr
or stdout
. I suggest using the subprocess
module instead. Here is a modification of your if __name__ == '__main__':
code block that I think accomplishes what you want:
if __name__ == '__main__':
if len(sys.argv) == 1:
# this is the normal situation
for _ in range(2):
# run this python script in a subprocess that will continue after this process exits
if sys.platform == 'linux':
subprocess.Popen([sys.executable, sys.argv[0], 'dummy_arg'], # add an additional arg as a flag
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
preexec_fn=os.setpgrp)
elif sys.platform == 'win32':
subprocess.Popen([sys.executable, sys.argv[0], 'dummy_arg'], # add an additional arg as a flag
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
creationflags=subprocess.DETACHED_PROCESS | subprocess.CREATE_NO_WINDOW)
else:
print('no match for platform')
else:
# this happens when there is an additional arg (arg is unused)
print('starting actual app')
run_app()
The above code uses the subprocess.Popen()
for each desired instance of the App
. The normal execution of the code will produce the subprocess
executions, but adds a dummy arg
. That dummy arg
forces the execution of the else:
code block, which just runs the App
.
There are different arguments to the Popen
call for different platforms to create a subprocess
that continues to run after the calling process exits. The linux
code block runs exactly as you want (for me). The win32
code starts the desired Apps
, but also opens another window for each instance of the App
. I haven't found a way to eliminate those extra windows.