current_geo_location_linux.cpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. /*
  2. This file is part of Telegram Desktop,
  3. the official desktop application for the Telegram messaging service.
  4. For license and copyright information please follow this link:
  5. https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
  6. */
  7. #include "platform/linux/current_geo_location_linux.h"
  8. #include "core/current_geo_location.h"
  9. #include "base/platform/linux/base_linux_library.h"
  10. #include <gio/gio.h>
  11. namespace Platform {
  12. namespace {
  13. typedef struct _GClueSimple GClueSimple;
  14. typedef struct _GClueLocation GClueLocation;
  15. typedef struct _GeocodeLocation GeocodeLocation;
  16. typedef struct _GeocodeReverse GeocodeReverse;
  17. typedef struct _GeocodePlace GeocodePlace;
  18. typedef enum {
  19. GCLUE_ACCURACY_LEVEL_NONE = 0,
  20. GCLUE_ACCURACY_LEVEL_COUNTRY = 1,
  21. GCLUE_ACCURACY_LEVEL_CITY = 4,
  22. GCLUE_ACCURACY_LEVEL_NEIGHBORHOOD = 5,
  23. GCLUE_ACCURACY_LEVEL_STREET = 6,
  24. GCLUE_ACCURACY_LEVEL_EXACT = 8,
  25. } GClueAccuracyLevel;
  26. void (*gclue_simple_new)(
  27. const char *desktop_id,
  28. GClueAccuracyLevel accuracy_level,
  29. GCancellable *cancellable,
  30. GAsyncReadyCallback callback,
  31. gpointer user_data);
  32. GClueSimple *(*gclue_simple_new_finish)(GAsyncResult *result, GError **error);
  33. GClueLocation *(*gclue_simple_get_location)(GClueSimple *simple);
  34. gdouble (*gclue_location_get_latitude)(GClueLocation *loc);
  35. gdouble (*gclue_location_get_longitude)(GClueLocation *loc);
  36. GeocodeLocation *(*geocode_location_new)(
  37. gdouble latitude,
  38. gdouble longitude,
  39. gdouble accuracy);
  40. GeocodeReverse *(*geocode_reverse_new_for_location)(
  41. GeocodeLocation *location);
  42. void (*geocode_reverse_resolve_async)(
  43. GeocodeReverse *object,
  44. GCancellable *cancellable,
  45. GAsyncReadyCallback callback,
  46. gpointer user_data);
  47. GeocodePlace *(*geocode_reverse_resolve_finish)(
  48. GeocodeReverse *object,
  49. GAsyncResult *res,
  50. GError **error);
  51. const char *(*geocode_place_get_street_address)(GeocodePlace *place);
  52. const char *(*geocode_place_get_town)(GeocodePlace *place);
  53. const char *(*geocode_place_get_country)(GeocodePlace *place);
  54. } // namespace
  55. void ResolveCurrentExactLocation(Fn<void(Core::GeoLocation)> callback) {
  56. static const auto Inited = [] {
  57. const auto lib = base::Platform::LoadLibrary(
  58. "libgeoclue-2.so.0",
  59. RTLD_NODELETE);
  60. return lib
  61. && LOAD_LIBRARY_SYMBOL(lib, gclue_simple_new)
  62. && LOAD_LIBRARY_SYMBOL(lib, gclue_simple_new_finish)
  63. && LOAD_LIBRARY_SYMBOL(lib, gclue_simple_get_location)
  64. && LOAD_LIBRARY_SYMBOL(lib, gclue_location_get_latitude)
  65. && LOAD_LIBRARY_SYMBOL(lib, gclue_location_get_longitude);
  66. }();
  67. if (!Inited) {
  68. callback({});
  69. return;
  70. }
  71. gclue_simple_new(
  72. QGuiApplication::desktopFileName().toUtf8().constData(),
  73. GCLUE_ACCURACY_LEVEL_EXACT,
  74. nullptr,
  75. GAsyncReadyCallback(+[](
  76. GObject *object,
  77. GAsyncResult* res,
  78. Fn<void(Core::GeoLocation)> *callback) {
  79. const auto callbackGuard = gsl::finally([&] {
  80. delete callback;
  81. });
  82. const auto simple = gclue_simple_new_finish(res, nullptr);
  83. if (!simple) {
  84. (*callback)({});
  85. return;
  86. }
  87. const auto simpleGuard = gsl::finally([&] {
  88. g_object_unref(simple);
  89. });
  90. const auto location = gclue_simple_get_location(simple);
  91. (*callback)({
  92. .point = {
  93. gclue_location_get_latitude(location),
  94. gclue_location_get_longitude(location),
  95. },
  96. .accuracy = Core::GeoLocationAccuracy::Exact,
  97. });
  98. }),
  99. new Fn(callback));
  100. }
  101. void ResolveLocationAddress(
  102. const Core::GeoLocation &location,
  103. const QString &language,
  104. Fn<void(Core::GeoAddress)> callback) {
  105. static const auto Inited = [] {
  106. const auto lib = base::Platform::LoadLibrary(
  107. "libgeocode-glib-2.so.0",
  108. RTLD_NODELETE) ?: base::Platform::LoadLibrary(
  109. "libgeocode-glib.so.0",
  110. RTLD_NODELETE);
  111. return lib
  112. && LOAD_LIBRARY_SYMBOL(lib, geocode_location_new)
  113. && LOAD_LIBRARY_SYMBOL(lib, geocode_reverse_new_for_location)
  114. && LOAD_LIBRARY_SYMBOL(lib, geocode_reverse_resolve_async)
  115. && LOAD_LIBRARY_SYMBOL(lib, geocode_reverse_resolve_finish)
  116. && LOAD_LIBRARY_SYMBOL(lib, geocode_place_get_street_address)
  117. && LOAD_LIBRARY_SYMBOL(lib, geocode_place_get_town)
  118. && LOAD_LIBRARY_SYMBOL(lib, geocode_place_get_country);
  119. }();
  120. if (!Inited) {
  121. callback({});
  122. return;
  123. }
  124. geocode_reverse_resolve_async(
  125. geocode_reverse_new_for_location(geocode_location_new(
  126. location.point.x(),
  127. location.point.y(),
  128. -1)),
  129. nullptr,
  130. GAsyncReadyCallback(+[](
  131. GeocodeReverse *reverse,
  132. GAsyncResult* res,
  133. Fn<void(Core::GeoAddress)> *callback) {
  134. const auto argsGuard = gsl::finally([&] {
  135. delete callback;
  136. g_object_unref(reverse);
  137. });
  138. const auto place = geocode_reverse_resolve_finish(
  139. reverse,
  140. res,
  141. nullptr);
  142. if (!place) {
  143. (*callback)({});
  144. return;
  145. }
  146. const auto placeGuard = gsl::finally([&] {
  147. g_object_unref(place);
  148. });
  149. const auto values = {
  150. geocode_place_get_street_address(place),
  151. geocode_place_get_town(place),
  152. geocode_place_get_country(place),
  153. };
  154. QStringList checked;
  155. for (const auto &value : values) {
  156. if (value) {
  157. const auto qt = QString::fromUtf8(value);
  158. if (!qt.isEmpty()) {
  159. checked.push_back(qt);
  160. }
  161. }
  162. }
  163. (*callback)({ .name = checked.join(u", "_q) });
  164. }),
  165. new Fn(callback));
  166. }
  167. } // namespace Platform