이 IRC 클라이언트를 만들면서 (가제 PRC) 처음부터 의도한 것은 기존 IRC 클라이언트보다 더 사용하기 쉽게 하자는 생각이었는데, 그 일환으로 초대 (INVITE) 이벤트도 텍스트 중심이 아닌 그래픽 인터페이스 중심으로 처리했다. 누군가에게 초대가 들어오면 그 사실만 알리는 게 아니라 초대받은 채널에 바로 입장할 수 있는 선택창을 띄우는 것.

PRC에서 초대를 받았을 때 뜨는 메시지
그런데 여기서 문제가 생겼다. 어느쪽 선택지를 고르든 무조건 연결이 끊어지는 결과가 발생하는 것. 왜 그럴까 하고 소스를 뒤지다가 원인을 발견했다. 프로그램 창을 닫으면 서버 연결을 끊는 이벤트 바인딩을 넣어놓았는데, 그 바인딩을 메시지박스에서 계승하고 있던 게 문제였다. 다음은 관련 코드.
class App:
def __init__(self, master):
"""초기 위젯 렌더링"""
self.master = master
#전체 창을 self.master 변수로 설정해서 같은 클래스 내 다른 함수에서도 부를 수 있게 한다
self.master.bind("<Destroy>",self.closeWindow)
#요 부분이 문제였다. closeWindow 함수는 연결을 끊는 함수인데 메시지박스에서 Yes를 선택하든 No를 선택하든 마찬가지로 창을 닫는 이벤트이니까 (<Destroy>) 같은 closeWindow 함수를 발동시킨다.
#중략
def closeWindow(self,event=None):
"""창이 닫히면 연결 끊기"""
if self.connected:
self.closeConnect()
#연결이 되어 있다면 끊으라는 명령
#후략
unbind로 바인딩을 끊으려고 해도 tkMessageBox 모듈로는 그게 좀 애매했다. tkMessageBox 모듈은 이런 식으로 불러오게 되어 있다.
import tkMessagebox
if tkMessageBox.askyesno(receivedInvite,askWhetherJoin):
self.joinChannel(channel)
위젯이면 unbind를 할 수 있겠지만 위젯이 아니라 모듈로 바로 작업하는 거라서 그렇게도 할 수 없었다. 그렇다고 창을 닫을 때 동시에 서버 연결을 끊지 않으면 핑 타임아웃이 될 때까지는 같은 닉으로 재접속할 수 없으므로 사용하기 쉬운 IRC 프로그램을 만든다는 취지에도 어울리지 않았다.
그래서 검색하다가 발견한 것이 윈도우 매니져 프로토콜이었다. 창 닫는 버튼을 누른다고 바로 창을 닫는 대신 다른 이벤트를 먼저 발생시키는 이벤트라고 한다. 즉, 창을 닫으면 지정 함수를 발동시키는 게 아니라 사용자가 창을 닫는다는 명령을 내리면 함수를 발동시킨다는 미묘하면서도 중요한 차이다.
예시를 보고 바인딩 대신 프로토콜 핸들러로 바꿔본 결과는 성공. 서버 접속을 끊는 함수 바인딩이 메시지박스에 계승되지 않아서 원하는 효과를 낼 수 있었다.
class App:
def __init__(self, master):
"""초기 위젯 렌더링"""
self.master = master
self.master.protocol("WM_DELETE_WINDOW",self.closeWindow)
#바인딩 대신 프로토콜 핸들러로 바꾸었다
#중략
def closeWindow(self,event=None):
"""창 닫으라는 명령을 받으면 연결 끊고 창 닫기"""
if self.connected:
self.closeConnect()
#연결이 되어 있다면 끊으라는 명령
self.master.event_generate("<Destroy>")
#그리고 창을 닫는다
#후략
해피엔딩~ 초대받은 채널에 입장을 선택하면 자동으로 입장하고, 거절하면 입장하지 않는다. 어느 쪽이든 연결은 끊어지지 않는다. 이벤트 바인딩은 메시지 박스에 계승이 되고 프로토콜 핸들러는 안 되는 이유는 알 듯 말 듯 하면서 잘 모르겠지만(..) 어쨌든 좋은 게 좋은 거 아닌가.

접속 해제 없는 자동 입장 성공!
이런 식으로 천천히 작업하다 보면 언젠가는 완성을 볼 수 있겠지. 그러다 보면 코딩도 좀 늘어 있을까. 몇 달만에 본 소스인데도 막상 작업을 시작하니 대충 뭘 했는지 생각나는 거 보면 역시 배우는 방법 중에서는 해보는 게 으뜸인 듯 싶다.





