2012-06-14 2 views
4

Gtk+ 코드는 Cairo 및 타이머를 사용하는 C으로 작성된 코드를 가지고 있습니다.GTK 위젯이 파괴되었는지 확인하는 방법

은 Gtk-CRITICAL ** : gtk_widget_queue_draw : 대부분의 시간을 때 내가 터미널에 다음과 같은 메시지가 얻을 닫기 응용 프로그램 아이콘을 클릭 주장`GTK_IS_WIDGET (위젯) '

실패 이제는 응용 프로그램을 닫는 순간 타이머가 작동되고 기본 창 위젯에 액세스하지만 이후 파괴 되었기 때문에 이것이 정상적으로 작동하고 있다고 가정합니다. Gtk 위젯이 여전히 유효하고 참조 될 수 있는지를 결정하는 일반적인 방법은 무엇입니까?

기분을 상하게하는 코드

은 여기에 있습니다 : 나는 믿고있어

gboolean rotate_cb(void *degrees) 
{ 
    rotation += DegreesToRadians((*(int*)(degrees))); 
    // Tell our window that it should repaint itself (ie. emit an expose event) 
    /* need to only call gtk_widget_queue_draw() if window is still valid/exists */ 
    gtk_widget_queue_draw(window); 
    return(TRUE); 
} 

window 여전히 활성 및 유효 여부를 테스트 할 수있는 방법이 있어야합니다?

답변

9

문제는 상당히 미묘합니다. 이는 일반적으로 GObject/GtkObject의 소유권 및 폐기 규칙 때문에 발생합니다. 내가 그들을 상기시켜 줄께 :

  • GObject는 단순히 카운트 참조됩니다. 카운트가 0에 도달하면 새로 생성 된 객체가 소멸됩니다. 새로 생성 된 객체의 카운트 수는 1입니다.
  • GInitiallyUnowned도 카운트됩니다. 또한 카운트가 0이되면 파괴됩니다. 그러나 새로 생성 된 객체는 플로팅 카운트입니다. 즉, 처음 카운트가 증가 할 때 실제로 증가하지는 않지만 부동 카운트는 인입니다. 즉, 정상 참조로 변환됩니다. 의

GtkObjectGInitiallyUnowned 개체, 그래서 그들은 수 부동 마법 있습니다.

그러나 당신은 아마 지금이 모든 것을 ... 알고, 내 질문 : 가시 주요 GtkWindow의 카운터를 소유

?

실제로 쉽습니다. GTK 프레임 워크에는 이러한 목록이 있으며 모든 표시 GtkWindow의 참조가 유지됩니다.그러나 다른 질문 :

언제 GTK 프레임 워크에서 GtkWindow의 참조를 해제합니까?

gtk_widget_destroy() 기능과 destroy 신호를 기억하십니까? 그것들을위한 것입니다 : GtkWindow 최상위를 제거하려면 gtk_widget_destroy()을 호출하면 실제 윈도우를 제거하고 객체에 대한 참조를 해제하는 GTK 프레임 워크가 수신하는 destroy 신호를 활성화합니다.

여기에 그 이유가 있습니다 : GTK 프레임 워크가 GtkWindow에 대한 유일한 기존 참조를 유지하면 개체가 실제로 해제됩니다. 그러면 타이머가 해당 타이머에 액세스하려고하면 창이 사라 지므로 실패합니다. 당신은 타이머를 시작 창에

  • 전화 g_object_ref()/g_object_ref_sink() :

    그리고 여기, 마지막으로,이 솔루션 (희망) 제공됩니다. 또한 윈도우의 신호에 대한 핸들러를 destroy에 등록하십시오.

  • destroy 창의 신호 처리기 : 창에서 g_object_unref()을 호출하고 타이머를 중지하십시오. 윈도우가 destroy 신호를 보내지 않고 파괴되지 않기 때문에

자연스럽게이 부분적인 해결책은 작동해야

  • 창의 destroy 신호 처리기를 등록한다.
  • destroy 창의 신호 처리기에서 타이머를 중지합니다.

실제로 포인터를 유지할 때 개체의 참조 카운터를 증가시키는 것이 좋습니다.

+0

매우 상세한 답변을 해주신 Rodrigo에게 감사드립니다. 나는 많은 것을 배웠고 그것을 고맙게 생각한다. – Chimera

+1

와우, 대단한 대답 이군. –

+0

매우 교육적인 대답, +1! – Nelson

2

더 이상 메모리에없는 객체의 상태, 즉 정의되지 않은 메모리 덩어리를 쿼리 할 수 ​​있기 때문에 방법이 없습니다. 그러한 기능은 실패 할 수있다. 동일한 메모리 주소에 다른 위젯이 생성 된 경우. 원칙적으로 매크로를 GTK_IS_WIDGET() 매크로로 사용할 수는 있지만 이 가장 자주 사용 되더라도 올바르게 작동하는지 보장하지 않습니다.

올바른 해결 방법은 window이 파괴되면 rotate_cb() 콜백을 제거하는 것입니다. 거기에 대한 "파괴"신호가 GtkWidget 있습니다. 따라서 "파괴"에 연결해야하고 해당 처리기에서 rotate_cb()을 제거하거나 rotate_cb()이 아무 것도하지 않도록하는 플래그를 설정하십시오.

+0

감사합니다. – Chimera

3

g_object_weak_ref() 또한 객체가 완료 될 때

약한 참조 통지에 사용되는 이러한 경우에 유용합니다.

당신은 그것이 그렇게 rotate_cb이 위젯이 파괴됩니다 한 번 호출 할 수 없습니다 파괴되기 전에 위젯에서 rotate_cb를 분리 (예. widget_destroy_cb에 의해) 약한 심판 콜백을 연결할 수 있습니다.

관련 문제