이 글은 간단한 예제를 통해 GDBus사용법을 설명한다.
GDBus는 GLib에 포함되어 제공되므로 먼저 관련 개발 패키지를 설치해야한다.
참고로 GLib은 GTK+ 프로젝트의 일부로 시작되었으며 비 GUI 적인 크로스 플랫폼 소프트웨어 유틸리티 세트이다. 플랫폼에 독립적인 응용프로그램을 만들 수 있도록 API를 제공한다.
https://developer.gnome.org/glib/
GIO는 다음의 Low-level D-Bus API 및
D-Bus Utilities — Various utilities related to D-Bus
D-Bus Addresses — D-Bus connection endpoints
D-Bus Introspection Data — Node and interface description data structures
GDBusError — Mapping D-Bus errors to and from GError
GDBusMessage — D-Bus Message
GDBusConnection — D-Bus Connections
GDBusMethodInvocation — Object for handling remote calls
GDBusServer — Helper for accepting connections
GDBusAuthObserver — Object used for authenticating connections
Highlevel D-Bus API를 제공한다.
Owning Bus Names — Simple API for owning bus names
Watching Bus Names — Simple API for watching bus names
GDBusInterface — Base type for D-Bus interfaces
GDBusInterfaceSkeleton — Service-side D-Bus interface
GDBusProxy — Client-side D-Bus interface proxy
GDBusObject — Base type for D-Bus objects
GDBusObjectSkeleton — Service-side D-Bus object
GDBusObjectProxy — Client-side D-Bus object
GDBusObjectManager — Base type for D-Bus object managers
GDBusObjectManagerServer — Service-side object manager
GDBusObjectManagerClient — Client-side object manager
간단한 예제를 통해 익혀보자.
운영체제: Linux(Ubuntu18.04)
IDE: QtCreator
아래의 명령으로 패키지를 설치할 수 있다.
sudo apt update
sudo apt install libglib2.0-dev
다른 DBus 바인딩과 비슷하게 GDBus도 DBus 인터페이스를 설명하는(객체의 인터페이스, 메소드 및 시그널등) XML형식의 문서 즉, DBus Introspection를 작성한다.
간단한 Introspection XML 예제.
net.Makersweb.Media.Playback.xml
<node>
<interface name="net.Makersweb.Media.Playback">
<method name="Play">
<arg name="index" direction="in" type="i"/>
</method>
<method name="Pause"></method>
<method name="Prev"></method>
<method name="Next"></method>
<signal name="PlaybackStateChanged">
<arg name="state" type="i"/>
</signal>
<property name="CurrentTrack" type="i" access="read"/>
</interface>
</node>
gdbus-codegen 사용
이 Introspection XML은 gdbus-codegen 을 통해서 D-Bus 인터페이스를위한 클라이언트 및 서버 측 래퍼를 생성할 수 있다.
위의 명령줄로 playback-generated.c 와 playback-generated.h 파일이 만들어 진다.
다음은 gdbus-codegen 옵션에 대한 간단한 설명이다.
QtCreator사용
IDE는 QtCreator를 사용하며 다음의 프로젝트파일(.pro)처럼 glib관련 라이브러리를 추가해줘야 한다.
xyz.pro
서버측 구현(Server Side)
생성된 playback-generated.h파일을 include하여 랩핑 함수들을 사용한다.
#include "playback-generated.h"
mediaplayback.cpp
세션 버스에 이름 등록
MediaPlayback::MediaPlayback()
{
/* Register bus name */
m_busId = g_bus_own_name (G_BUS_TYPE_SESSION,
"net.Makersweb.Examples.Media",
(GBusNameOwnerFlags)(G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT | G_BUS_NAME_OWNER_FLAGS_REPLACE),
on_bus_acquired,
on_name_acquired,
nullptr,
nullptr,
nullptr);
}
bus_type에 의해 지정된 버스에서 이름 획득을 시작하고 이름이 획득되면 각각 on_bus_acquired 및 on_name_acquired가 호출된다.
examplePlayback * MediaPlayback::m_obj = nullptr;
void MediaPlayback::on_bus_acquired(GDBusConnection *connection, const gchar *name, gpointer user_data)
{
g_print ("Acquired a message bus connection\n");
m_obj = example_playback_skeleton_new();
example_playback_set_current_track(m_obj, 0);
/* Handle Play() D-Bus method invocations on the .Playback interface */
g_signal_connect (m_obj,
"handle-play",
G_CALLBACK (on_handle_play),
nullptr); /* user_data */
GError *error = nullptr;
if (!g_dbus_interface_skeleton_export ( G_DBUS_INTERFACE_SKELETON (m_obj),
connection,
"/path/of/dbus_object",
&error))
{
/* handle error */
}
}
D-Bus인터페이스 Play()의 콜백함수
gboolean MediaPlayback::on_handle_play(examplePlayback *interface, GDBusMethodInvocation *invocation, gint trackIndex, gpointer user_data)
{
if(trackIndex >= 0){
/* Play track Sequence */
example_playback_set_current_track(m_obj, trackIndex);
/* D-Bus 메서드 호출 완료 함수 */
example_playback_complete_play(interface, invocation);
}
else {
g_dbus_method_invocation_return_dbus_error (invocation,
"Media.Playback.Error.play",
"invalid track.");
}
return TRUE;
}
main함수
#include "mediaplayback.h"
gint main (gint argc, gchar *argv[]){
GMainLoop *loop;
guint id;
g_type_init ();
loop = g_main_loop_new (nullptr, FALSE);
MediaPlayback * playback = new MediaPlayback;
g_main_loop_run (loop);
g_bus_unown_name (id);
g_main_loop_unref (loop);
return 0;
}
클라이언트측 (Client Side)