Language/Python

[pywebview] "X" 버튼 (close) 누르면 webview hide 하도록 구현

TechNote.kr 2021. 9. 12. 21:27

 

Window UI 에서 오른쪽 위 X 버튼을 누르면 창이 사라지고 tray 의 Show 메뉴를 누르면 다시 나타나는 기능을 구현하고자 한다. 

 

이를 위해 링크(API | pywebview (flowrl.com))를 검토해 보니 closing event를 처리하는 on_closing 내에서 False 를 return 하면 close 처리를 하지 않는다는 것을 확인했다. 

이에 아래와 같이 on_closing 구문내에 hide 기능을 넣고 False를 return 하면 될 것으로 생각하고 구현하였지만, 해당 구문을 타게 되면 CPU 를 100%를 먹으면서 프로그램이 "응답 없음"이 되버리면서 죽어 버렸다. 

def webview_subprocess(conn_parent, conn_child):
...
    window.closing += on_closing
 
def on_closing():
    webview.windows[0].hide()
    return False

인터넷을 찾아보니 유사한 이슈를 처리한 이력을 찾을 수 있었다. pywebview 제작자가 답변한 내용이다. 

https://github.com/r0x0r/pywebview/issues/573

on_closing 은 별도의 thread로 처리되기에 해당 thread 에서 webview window 를 제대로 제어하지 못한다는 것으로 이해하였다.

그래서 on_closing thread에서 바로 hide api를 호출하여 window 를 제어하는 방식이 아니라 on_closing thread에서 webview window 가 실행되고 있는 thread 로 hide cmd 를 전송해 hide 시키는 방식을 생각하였다. 

프로그램 시작시 PIPE를 생성하여 main process (tray 구동) 와 sub process(webview 구동) 가 나눠 가지는데, 
이 때 webview쪽으로 cmd(hide/show)를 전송하기 위해 사용하는 main process 쪽 pipe를 sub process 의 on_closing 에서도 사용할 수 있게 넘겨주였다. 

즉, parent pipe와 child pipe를 모두 subprocess 쪽으로 넘겨준다.

def webview_subprocess(conn_parent, conn_child):
    window = webview.create_window('TechNote', 'https://technote.kr')
    window.closing += on_closing
    conn.parent = conn_parent
    conn.child = conn_child
    webview.start(cmd_recv, [], gui='cef', debug=True)


if __name__ == '__main__':
    conn.parent, conn.child = Pipe()

    subprocess_handler = Process(target=webview_subprocess, args=(conn.parent, conn.child))
    subprocess_handler.start()

이 후 같은 subprocess 내지만 다른 thread 인 on_closing 에서 cmd_recv 로 cmd를 전송하기 위해 parent pipe와 child pipe를 이용하게 한다. 

def on_closing():
    send_cmd_to_window('hide')
    return False

def send_cmd_to_window(cmd):
    conn.parent.send(cmd)

def cmd_recv():
    while True:
        cmd = conn.child.recv()
        if cmd == 'show':
            print('Show - pywebview')
            webview.windows[0].show()
        elif cmd == 'hide':
            print('Hide - pywebview')
            webview.windows[0].hide()

이를 통해 on_closing 내에서도 webview window를 hide 할 수 있도록 구현할 수 있다. 

hide window in on_closing routine · TechNoteGit/pywebview_example@71ac867 (github.com)