Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
location.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2011-2014 Henrik Andersson.
4 Copyright (C) 2012 Robert Bieber.
5 Copyright (C) 2012, 2014, 2016-2018 Tobias Ellinghaus.
6 Copyright (C) 2013 johannes hanika.
7 Copyright (C) 2013-2016 Roman Lebedev.
8 Copyright (C) 2013 Simon Spannagel.
9 Copyright (C) 2018 Benoit Brummer.
10 Copyright (C) 2018 Maurizio Paglia.
11 Copyright (C) 2018 rawfiner.
12 Copyright (C) 2019, 2025 Aurélien PIERRE.
13 Copyright (C) 2019-2021 Pascal Obry.
14 Copyright (C) 2019 Peter Budai.
15 Copyright (C) 2020 Aldric Renaudin.
16 Copyright (C) 2021-2022 Diederik Ter Rahe.
17 Copyright (C) 2021 Philippe Weyland.
18 Copyright (C) 2021 Ralf Brown.
19 Copyright (C) 2022 luzpaz.
20 Copyright (C) 2022 Martin Bařinka.
21 Copyright (C) 2022 Miloš Komarčević.
22
23 darktable is free software: you can redistribute it and/or modify
24 it under the terms of the GNU General Public License as published by
25 the Free Software Foundation, either version 3 of the License, or
26 (at your option) any later version.
27
28 darktable is distributed in the hope that it will be useful,
29 but WITHOUT ANY WARRANTY; without even the implied warranty of
30 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 GNU General Public License for more details.
32
33 You should have received a copy of the GNU General Public License
34 along with darktable. If not, see <http://www.gnu.org/licenses/>.
35*/
36
37#include "metadata/geo.h"
38#include "control/settings.h"
39#include "common/curl_tools.h"
40#include "common/glib_utils.h"
41#include "system/macros.h"
43#include "common/utility.h"
44#include "common/conf.h"
45#include "control/jobs.h"
46#include "libs/lib.h"
47#include "libs/lib_api.h"
48#include "views/view.h"
49#include <curl/curl.h>
50#include <gdk/gdkkeysyms.h>
51#include "gui/window_manager.h"
53#include "widgets/container.h"
55#include "control/signal.h"
56
57DT_MODULE(1)
58
68
80
81typedef struct dt_lib_location_t
82{
83 GtkEntry *search;
86
87 GList *places;
88
89 /* result buffer written to by */
90 gchar *response;
92
93 /* pin, track or polygon currently shown on the map */
94 GObject *marker;
96
97 /* remember the currently selected search result so we can put it into a preset */
99
100 // place used to keep biggest polygon
103
109
110#define LIMIT_RESULT 5
111
112/* entry value committed, perform a search */
113static void _lib_location_entry_activated(GtkButton *button, gpointer user_data);
114
115static gboolean _lib_location_result_item_activated(GtkButton *button, GdkEventButton *ev, gpointer user_data);
116
117static void _lib_location_parser_start_element(GMarkupParseContext *cxt, const char *element_name,
118 const char **attribute_names, const gchar **attribute_values,
119 gpointer user_data, GError **error);
120
121static void clear_search(dt_lib_location_t *lib);
122
123const char *name(struct dt_lib_module_t *self)
124{
125 return _("find location");
126}
127
128const char **views(dt_lib_module_t *self)
129{
130 static const char *v[] = {"map", NULL};
131 return v;
132}
133
138
139
141{
143 gtk_entry_set_text(lib->search, "");
144 clear_search(lib);
145}
146
148{
149 return 999;
150}
151
152/*
153 https://nominatim.openstreetmap.org/search/norrköping?format=xml&limit=5
154 */
156{
157 self->data = calloc(1, sizeof(dt_lib_location_t));
158 dt_lib_location_t *lib = self->data;
159
160 self->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
161
162 /* add search box */
163 lib->search = GTK_ENTRY(gtk_entry_new());
165 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(lib->search), FALSE, FALSE, 0);
166
167 g_signal_connect(G_OBJECT(lib->search), "activate", G_CALLBACK(_lib_location_entry_activated),
168 (gpointer)self);
169
170 /* add result vbox */
171 lib->result = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
172 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(lib->result), TRUE, FALSE, 0);
173}
174
176{
177 if(IS_NULL_PTR(self->data)) return;
178 dt_free(self->data);
179}
180
181static gboolean _event_box_enter_leave(GtkWidget *widget, GdkEventCrossing *event, gpointer user_data)
182{
183 if(event->type == GDK_ENTER_NOTIFY)
184 gtk_widget_set_state_flags(widget, GTK_STATE_FLAG_PRELIGHT, FALSE);
185 else
186 gtk_widget_unset_state_flags(widget, GTK_STATE_FLAG_PRELIGHT);
187
188 return FALSE;
189}
190
192{
193 GtkWidget *eb, *vb, *w;
194 eb = gtk_event_box_new();
195 gtk_widget_set_name(eb, "dt-map-location");
196 g_signal_connect(G_OBJECT(eb), "enter-notify-event", G_CALLBACK(_event_box_enter_leave), NULL);
197 g_signal_connect(G_OBJECT(eb), "leave-notify-event", G_CALLBACK(_event_box_enter_leave), NULL);
198
199 vb = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
200
201 /* add name */
202 w = gtk_label_new(place->name);
203 gtk_label_set_line_wrap(GTK_LABEL(w), TRUE);
204 gtk_widget_set_halign(w, GTK_ALIGN_START);
205 g_object_set(G_OBJECT(w), "xalign", 0.0, (gchar *)0);
206 gtk_box_pack_start(GTK_BOX(vb), w, FALSE, FALSE, 0);
207
208 /* add location coord */
209 gchar *lat = dt_util_latitude_str(place->lat);
210 gchar *lon = dt_util_longitude_str(place->lon);
211 gchar *location = g_strconcat(lat, ", ", lon, NULL);
212 w = gtk_label_new(location);
213 dt_free(lat);
214 dt_free(lon);
215 dt_free(location);
216 gtk_label_set_line_wrap(GTK_LABEL(w), TRUE);
217 gtk_widget_set_halign(w, GTK_ALIGN_START);
218 gtk_box_pack_start(GTK_BOX(vb), w, FALSE, FALSE, 0);
219
220 /* setup layout */
221 gtk_container_add(GTK_CONTAINER(eb), vb);
222
223 gtk_widget_show_all(eb);
224
225 /* connect button press signal for result item */
227 lib->callback_params = g_list_append(lib->callback_params, param);
228 param->lib = lib;
229 param->result = place;
230 g_signal_connect(G_OBJECT(eb), "button-press-event", G_CALLBACK(_lib_location_result_item_activated),
231 (gpointer)param);
232
233
234 return eb;
235}
236
237static size_t _lib_location_curl_write_data(void *buffer, size_t size, size_t nmemb, void *userp)
238{
239 dt_lib_location_t *lib = (dt_lib_location_t *)userp;
240
241 char *newdata = g_malloc0(lib->response_size + nmemb + 1);
242 if(!IS_NULL_PTR(lib->response)) memcpy(newdata, lib->response, lib->response_size);
243 memcpy(newdata + lib->response_size, buffer, nmemb);
244 dt_free(lib->response);
245 lib->response = newdata;
246 lib->response_size += nmemb;
247
248 return nmemb;
249}
250
251
252static GMarkupParser _lib_location_parser = { _lib_location_parser_start_element, NULL, NULL, NULL, NULL };
253
254
256{
257 switch(place->type)
258 {
260 return 18;
261
263 return 17;
264
266 return 12;
267
271 default:
272 return 8;
273 }
274
275 /* should never get here */
276 return 0;
277}
278
280{
281 if(lib->marker_type == MAP_DISPLAY_NONE) return;
283 g_object_unref(lib->marker);
284 lib->marker = NULL;
286}
287
289{
290 dt_free(location->name);
291 g_list_free_full(location->marker_points, dt_free_gpointer);
292 location->marker_points = NULL;
293 dt_free(location);
294}
295
297{
298 dt_free(lib->response);
299 lib->response_size = 0;
300 lib->selected_location = NULL;
301
302 g_list_free_full(lib->places, (GDestroyNotify)free_location);
303 lib->places = NULL;
304
305 dt_gui_container_destroy_children(GTK_CONTAINER(lib->result));
306 g_list_free_full(lib->callback_params, dt_free_gpointer);
307 lib->callback_params = NULL;
308
309 _clear_markers(lib);
310}
311
313{
314 if(isnan(p->bbox.lon1) || isnan(p->bbox.lat1) || isnan(p->bbox.lon2) || isnan(p->bbox.lat2))
315 {
316 int32_t zoom = _lib_location_place_get_zoom(p);
318 }
319 else
320 {
321 dt_view_map_center_on_bbox(dt_view_manager_get_global(), p->bbox.lon1, p->bbox.lat1, p->bbox.lon2, p->bbox.lat2);
322 }
323
324 _clear_markers(lib);
325
326 lib->marker = dt_view_map_add_marker(dt_view_manager_get_global(), p->marker_type, p->marker_points);
327 lib->marker_type = p->marker_type;
328 lib->selected_location = p;
329
331 p->marker_type == MAP_DISPLAY_POLYGON ? p->marker_points : NULL);
332}
333
334/* called when search job has been processed and
335 result has been parsed */
336static void _lib_location_search_finish(gpointer user_data)
337{
338 dt_lib_module_t *self = (dt_lib_module_t *)user_data;
340
341 /* check if search gave us some result */
342 if(IS_NULL_PTR(lib->places)) return;
343
344 /* for each location found populate the result list */
345 for(const GList *item = lib->places; item; item = g_list_next(item))
346 {
347 _lib_location_result_t *place = (_lib_location_result_t *)item->data;
348 gtk_box_pack_start(GTK_BOX(lib->result), _lib_location_place_widget_new(lib, place), TRUE, TRUE, 0);
349 gtk_widget_show(lib->result);
350 }
351
352 /* if we only got one search result back lets
353 set center location and zoom based on place type */
355 {
357 _show_location(lib, place);
358 }
359}
360
361static gboolean _lib_location_search(gpointer user_data)
362{
363 GMarkupParseContext *ctx = NULL;
364 CURL *curl = NULL;
365 CURLcode res;
366 GError *err = NULL;
367
368 dt_lib_module_t *self = (dt_lib_module_t *)user_data;
370 gchar *query = NULL, *text = NULL;
371
372 /* get escaped search text */
373 text = g_uri_escape_string(gtk_entry_get_text(lib->search), NULL, FALSE);
374
375 if(!(text && *text)) goto bail_out;
376
377 /* clean up previous results before adding new */
378 clear_search(lib);
379
380 /* build the query url */
381 const char *search_url = dt_conf_get_string_const("plugins/map/geotagging_search_url");
382 query = g_strdup_printf(search_url, text, LIMIT_RESULT);
383 /* load url */
384 curl = curl_easy_init();
385 if(IS_NULL_PTR(curl)) goto bail_out;
386
387 dt_curl_init(curl, FALSE);
388
389 curl_easy_setopt(curl, CURLOPT_URL, query);
390 curl_easy_setopt(curl, CURLOPT_WRITEDATA, lib);
391 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, _lib_location_curl_write_data);
392 curl_easy_setopt(curl, CURLOPT_USERAGENT, (char *)darktable_package_string);
393 curl_easy_setopt(curl, CURLOPT_TIMEOUT, 20L);
394
395 res = curl_easy_perform(curl);
396 if(res != 0) goto bail_out;
397
398 if(!lib->response) goto bail_out;
399
400 /* parse xml response and populate the result list */
401 ctx = g_markup_parse_context_new(&_lib_location_parser, 0, lib, NULL);
402 g_markup_parse_context_parse(ctx, lib->response, lib->response_size, &err);
403 if(err) goto bail_out;
404
405 /* add the places into the result list */
406 GList *item = lib->places;
407 if(IS_NULL_PTR(item)) goto bail_out;
408
409// while(item)
410// {
411// _lib_location_result_t *p = (_lib_location_result_t *)item->data;
412// fprintf(stderr, "(%f,%f) %s\n", p->lon, p->lat, p->name);
413// item = g_list_next(item);
414// }
415
416/* cleanup an exit search job */
417bail_out:
418 if(err)
419 {
420 fprintf(stderr, "location search: %s\n", err->message);
421 g_error_free(err);
422 }
423
424 if(curl) curl_easy_cleanup(curl);
425
426 dt_free(text);
427 dt_free(query);
428
429 if(ctx) g_markup_parse_context_free(ctx);
430
431 /* enable the widgets */
432 gtk_widget_set_sensitive(GTK_WIDGET(lib->search), TRUE);
433 // gtk_widget_set_sensitive(lib->result, FALSE);
434
435 return FALSE;
436}
437
438gboolean _lib_location_result_item_activated(GtkButton *button, GdkEventButton *ev, gpointer user_data)
439{
441 dt_lib_location_t *lib = param->lib;
442 _lib_location_result_t *result = param->result;
443 _show_location(lib, result);
444 return TRUE;
445}
446
447void _lib_location_entry_activated(GtkButton *button, gpointer user_data)
448{
449 dt_lib_module_t *self = (dt_lib_module_t *)user_data;
451 const gchar *text = gtk_entry_get_text(lib->search);
452 if(IS_NULL_PTR(text) || text[0] == '\0') return;
453
454 /* lock the widget while search job is performing */
455 gtk_widget_set_sensitive(GTK_WIDGET(lib->search), FALSE);
456 // gtk_widget_set_sensitive(lib->result, FALSE);
457
458 /* start a bg job for fetching results of a search */
459 g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, _lib_location_search, user_data, _lib_location_search_finish);
460}
461
462
463static void _lib_location_parser_start_element(GMarkupParseContext *cxt, const char *element_name,
464 const char **attribute_names, const gchar **attribute_values,
465 gpointer user_data, GError **e)
466{
467 dt_lib_location_t *lib = (dt_lib_location_t *)user_data;
468
469 /* only interested in place element */
470 if(strcmp(element_name, "place") != 0) return;
471
472 // used to keep the biggest polygon
473 lib->marker_points = NULL;
474
475 /* create new place */
476 _lib_location_result_t *place = g_malloc0(sizeof(_lib_location_result_t));
477 if(IS_NULL_PTR(place)) return;
478
479 place->lon = NAN;
480 place->lat = NAN;
481 place->bbox.lon1 = NAN;
482 place->bbox.lat1 = NAN;
483 place->bbox.lon2 = NAN;
484 place->bbox.lat2 = NAN;
486 place->marker_points = NULL;
487
488 gboolean show_outline = dt_conf_get_bool("plugins/map/show_outline");
489 int max_outline_nodes = dt_conf_get_int("plugins/map/max_outline_nodes");
490
491 /* handle the element attribute values */
492 const gchar **aname = attribute_names;
493 const gchar **avalue = attribute_values;
494 if(*aname)
495 {
496 while(*aname)
497 {
498 if(strcmp(*aname, "display_name") == 0)
499 {
500 place->name = g_strdup(*avalue);
501 if(!(place->name)) goto bail_out;
502 }
503 else if(strcmp(*aname, "lon") == 0)
504 place->lon = g_strtod(*avalue, NULL);
505 else if(strcmp(*aname, "lat") == 0)
506 place->lat = g_strtod(*avalue, NULL);
507 else if(strcmp(*aname, "boundingbox") == 0)
508 {
509 char *endptr;
510 float lon1, lat1, lon2, lat2;
511
512 lat1 = g_ascii_strtod(*avalue, &endptr);
513 if(*endptr != ',') goto broken_bbox;
514 endptr++;
515
516 lat2 = g_ascii_strtod(endptr, &endptr);
517 if(*endptr != ',') goto broken_bbox;
518 endptr++;
519
520 lon1 = g_ascii_strtod(endptr, &endptr);
521 if(*endptr != ',') goto broken_bbox;
522 endptr++;
523
524 lon2 = g_ascii_strtod(endptr, &endptr);
525 if(*endptr != '\0') goto broken_bbox;
526
527 place->bbox.lon1 = lon1;
528 place->bbox.lat1 = lat1;
529 place->bbox.lon2 = lon2;
530 place->bbox.lat2 = lat2;
531broken_bbox:
532 ;
533 }
534 // only use the first 'geotext' entry
535 else if(show_outline &&
536 strcmp(*aname, "geotext") == 0 &&
538 {
539 if(g_str_has_prefix(*avalue, "POINT"))
540 {
541 char *endptr;
542 float lon = g_ascii_strtod(*avalue + strlen("POINT("), &endptr);
543 float lat = g_ascii_strtod(endptr, &endptr);
544 if(*endptr == ')')
545 {
548 p->lon = lon;
549 p->lat = lat;
550 place->marker_points = g_list_append(place->marker_points, p);
551 }
552 }
553 else if(g_str_has_prefix(*avalue, "LINESTRING")
554#ifdef HAVE_OSMGPSMAP_110_OR_NEWER
555 || g_str_has_prefix(*avalue, "POLYGON")
556 || g_str_has_prefix(*avalue, "MULTIPOLYGON")
557#endif
558 )
559 {
560 gboolean error = FALSE;
561 const char *startptr = *avalue;
562 char *endptr;
563 while(startptr && (*startptr == ' ' || *startptr == '(' || (*startptr >= 'A' && *startptr <= 'Z')))
564 startptr++;
565
566 int i = 0;
567 while(1)
568 {
569 float lon = g_ascii_strtod(startptr, &endptr);
570 float lat = g_ascii_strtod(endptr, &endptr);
571
572 if(*endptr == ')') // TODO: support holes in POLYGON and several forms in MULTIPOLYGON?
573 {
574 // doesn't really support MULTIPOLYGON, just keeps the biggect one
575 const int old_mp = g_list_length(lib->marker_points);
576 const int new_mp = g_list_length(place->marker_points);
577 if(g_str_has_prefix(endptr, ")),((") || g_str_has_prefix(endptr, "),("))
578 {
579 if(new_mp > old_mp)
580 {
581 g_list_free_full(lib->marker_points, dt_free_gpointer);
582 lib->marker_points = place->marker_points;
583 }
584 else
585 g_list_free_full(place->marker_points, dt_free_gpointer);
586 place->marker_points = NULL;
587 startptr = endptr + (g_str_has_prefix(endptr, ")),((") ? 5 : 3);
588 continue;
589 }
590 else
591 {
592 if(new_mp > old_mp)
593 {
594 g_list_free_full(lib->marker_points, dt_free_gpointer);
595 lib->marker_points = NULL;
596 }
597 else
598 {
599 g_list_free_full(place->marker_points, dt_free_gpointer);
600 place->marker_points = lib->marker_points;
601 }
602 lib->marker_points = NULL;
603 break;
604 }
605 }
606 if(*endptr != ',' || i > max_outline_nodes) // don't go too big for speed reasons
607 {
608 error = TRUE;
609 break;
610 }
612 p->lon = lon;
613 p->lat = lat;
614 place->marker_points = g_list_prepend(place->marker_points, p);
615 startptr = endptr+1;
616 i++;
617 }
618 place->marker_points = g_list_reverse(place->marker_points);
619 if(error)
620 {
621 g_list_free_full(place->marker_points, dt_free_gpointer);
622 place->marker_points = NULL;
623 }
624 else
625 {
626 place->marker_type = g_str_has_prefix(*avalue, "LINESTRING") ? MAP_DISPLAY_TRACK : MAP_DISPLAY_POLYGON;
627 }
628 }
629 else
630 {
631 gchar *s = g_strndup(*avalue, 100);
632 fprintf(stderr, "unsupported outline: %s%s\n", s, strlen(s) == strlen(*avalue) ? "" : " ...");
633 dt_free(s);
634 }
635 }
636 else if(strcmp(*aname, "type") == 0)
637 {
638
639 if(strcmp(*avalue, "village") == 0)
641 else if(strcmp(*avalue, "hamlet") == 0)
642 place->type = LOCATION_TYPE_HAMLET;
643 else if(strcmp(*avalue, "city") == 0)
644 place->type = LOCATION_TYPE_CITY;
645 else if(strcmp(*avalue, "administrative") == 0)
647 else if(strcmp(*avalue, "residental") == 0) // for backward compatibility
649 else if(strcmp(*avalue, "residential") == 0)
651 }
652
653 aname++;
654 avalue++;
655 }
656 }
657
658 /* check if we got sane data */
659 if(isnan(place->lon) || isnan(place->lat)) goto bail_out;
660
661 /* add place to result list */
662 lib->places = g_list_append(lib->places, place);
663
664 return;
665
666bail_out:
667 dt_free(place->name);
668 dt_free(place);
669}
670
680
682{
685
686 // we have nothing to store when the user hasn't picked a search result
687 if(IS_NULL_PTR(location)) return NULL;
688
689 const size_t size_fixed = sizeof(struct params_fixed_t);
690 const size_t size_name = strlen(location->name) + 1;
691 const size_t size_points = 2 * sizeof(float) * g_list_length(location->marker_points);
692 const size_t size_total = size_fixed + size_name + size_points;
693
694 void *params = malloc(size_total);
695 struct params_fixed_t *params_fixed = (struct params_fixed_t *)params;
696 params_fixed->relevance = location->relevance;
697 params_fixed->type = location->type;
698 params_fixed->lon = location->lon;
699 params_fixed->lat = location->lat;
700 params_fixed->bbox.lon1 = location->bbox.lon1;
701 params_fixed->bbox.lat1 = location->bbox.lat1;
702 params_fixed->bbox.lon2 = location->bbox.lon2;
703 params_fixed->bbox.lat2 = location->bbox.lat2;
704 params_fixed->marker_type = location->marker_type;
705
706 memcpy((uint8_t *)params + size_fixed, location->name, size_name);
707
708 float *points = (float *)((uint8_t *)params + size_fixed + size_name);
709 for(GList *iter = location->marker_points; iter; iter = g_list_next(iter), points += 2)
710 {
712 points[0] = point->lat;
713 points[1] = point->lon;
714 }
715
716 *size = size_total;
717 return params;
718}
719
720int set_params(dt_lib_module_t *self, const void *params, int size)
721{
723
724 const size_t size_fixed = sizeof(struct params_fixed_t);
725
726 if(size < size_fixed) return 1;
727
728 const struct params_fixed_t *params_fixed = (struct params_fixed_t *)params;
729 const char *name = (char *)((uint8_t *)params + size_fixed);
730 const size_t size_name = strlen(name) + 1;
731
732 if(size_fixed + size_name > size) return 1;
733
734 const size_t size_points = size - (size_fixed + size_name);
735
736 if(size_points % 2 * sizeof(float) != 0) return 1;
737
739
740 location->relevance = params_fixed->relevance;
741 location->type = params_fixed->type;
742 location->lon = params_fixed->lon;
743 location->lat = params_fixed->lat;
744 location->bbox.lon1 = params_fixed->bbox.lon1;
745 location->bbox.lat1 = params_fixed->bbox.lat1;
746 location->bbox.lon2 = params_fixed->bbox.lon2;
747 location->bbox.lat2 = params_fixed->bbox.lat2;
748 location->marker_type = params_fixed->marker_type;
749 location->name = g_strdup(name);
750 location->marker_points = NULL;
751
752 for(const float *points = (float *)((uint8_t *)params + size_fixed + size_name); (uint8_t *)points < (uint8_t *)params + size; points += 2)
753 {
755 p->lat = points[0];
756 p->lon = points[1];
757 location->marker_points = g_list_prepend(location->marker_points, p);
758 }
759 location->marker_points = g_list_reverse(location->marker_points);
760
761 clear_search(lib);
762 lib->places = g_list_append(lib->places, location);
763 gtk_entry_set_text(lib->search, "");
765
766 return 0;
767}
768
769// clang-format off
770// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
771// vim: shiftwidth=2 expandtab tabstop=2 cindent
772// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
773// clang-format on
void dt_accels_disconnect_on_text_input(GtkWidget *widget)
Disconnect accels while a text or search entry has the focus, and reconnect them when it loses it....
Handle default and user-set shortcuts (accelerators)
static void error(char *msg)
Definition ashift_lsd.c:202
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
const float v
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
Definition colorspaces.h:98
int dt_conf_get_bool(const char *name)
int dt_conf_get_int(const char *name)
Integer for name, clamped to the bounds declared in the XML.
const char * dt_conf_get_string_const(const char *name)
Borrow the stored string for name without copying it.
const char darktable_package_string[]
void dt_gui_container_destroy_children(GtkContainer *container)
Definition container.c:80
void dt_curl_init(CURL *curl, gboolean verbose)
Definition curl_tools.c:35
struct dt_view_manager_t * dt_view_manager_get_global(void)
Definition darktable.c:599
const int res
Definition dtpthread.h:351
dt_geo_map_display_t
Definition geo.h:26
@ MAP_DISPLAY_POLYGON
Definition geo.h:30
@ MAP_DISPLAY_NONE
Definition geo.h:27
@ MAP_DISPLAY_POINT
Definition geo.h:28
@ MAP_DISPLAY_TRACK
Definition geo.h:29
#define g_list_is_singleton(list)
Definition glib_utils.h:33
static void _show_location(dt_lib_location_t *lib, _lib_location_result_t *p)
Definition location.c:312
void gui_reset(dt_lib_module_t *self)
Definition location.c:140
int set_params(dt_lib_module_t *self, const void *params, int size)
Definition location.c:720
static void clear_search(dt_lib_location_t *lib)
Definition location.c:296
void * get_params(dt_lib_module_t *self, int *size)
Definition location.c:681
static void _clear_markers(dt_lib_location_t *lib)
Definition location.c:279
static size_t _lib_location_curl_write_data(void *buffer, size_t size, size_t nmemb, void *userp)
Definition location.c:237
#define LIMIT_RESULT
Definition location.c:110
void gui_cleanup(dt_lib_module_t *self)
Definition location.c:175
static void _lib_location_parser_start_element(GMarkupParseContext *cxt, const char *element_name, const char **attribute_names, const gchar **attribute_values, gpointer user_data, GError **error)
Definition location.c:463
static void _lib_location_entry_activated(GtkButton *button, gpointer user_data)
Definition location.c:447
static GMarkupParser _lib_location_parser
Definition location.c:252
uint32_t container(dt_lib_module_t *self)
Definition location.c:134
static gboolean _lib_location_result_item_activated(GtkButton *button, GdkEventButton *ev, gpointer user_data)
Definition location.c:438
static void _lib_location_search_finish(gpointer user_data)
Definition location.c:336
static gboolean _event_box_enter_leave(GtkWidget *widget, GdkEventCrossing *event, gpointer user_data)
Definition location.c:181
static void free_location(_lib_location_result_t *location)
Definition location.c:288
void gui_init(dt_lib_module_t *self)
Definition location.c:155
int position()
Definition location.c:147
const char ** views(dt_lib_module_t *self)
Definition location.c:128
_lib_location_type_t
Definition location.c:60
@ LOCATION_TYPE_UNKNOWN
Definition location.c:66
@ LOCATION_TYPE_VILLAGE
Definition location.c:61
@ LOCATION_TYPE_ADMINISTRATIVE
Definition location.c:64
@ LOCATION_TYPE_RESIDENTIAL
Definition location.c:65
@ LOCATION_TYPE_CITY
Definition location.c:63
@ LOCATION_TYPE_HAMLET
Definition location.c:62
float lat
Definition location.c:3
static int32_t _lib_location_place_get_zoom(_lib_location_result_t *place)
Definition location.c:255
static gboolean _lib_location_search(gpointer user_data)
Definition location.c:361
static GtkWidget * _lib_location_place_widget_new(dt_lib_location_t *lib, _lib_location_result_t *place)
Definition location.c:191
float lon
Definition location.c:2
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
Definition macros.h:96
static void dt_free_gpointer(gpointer ptr)
g_free() one pointer, with the signature GDestroyNotify wants.
Definition mem_alloc.h:184
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
Definition mem_alloc.h:171
size_t size
Definition mipmap_cache.c:3
#define DT_MODULE(MODVER)
Instantiate the version handshake every module must export. Use once, at file scope,...
const char * name
Definition pdf.h:90
#define DT_DEBUG_CONTROL_SIGNAL_RAISE(ctlsig, signal,...)
Definition signal.h:386
struct dt_control_signal_t * dt_control_signal_get_global(void)
Definition darktable.c:616
@ DT_SIGNAL_LOCATION_CHANGED
Definition signal.h:311
float dt_aligned_pixel_simd_t __attribute__((vector_size(16), aligned(16)))
Apply one channel's tone curve to each of the three colour channels, or pass the channel through unto...
Definition simd.h:55
const float const float param
dt_lib_location_t * lib
Definition location.c:106
_lib_location_result_t * result
Definition location.c:107
dt_geo_map_display_t marker_type
Definition location.c:76
_lib_location_type_t type
Definition location.c:72
dt_map_box_t bbox
Definition location.c:75
gchar * response
Definition location.c:90
size_t response_size
Definition location.c:91
_lib_location_result_t * selected_location
Definition location.c:98
GtkWidget * result
Definition location.c:84
dt_geo_map_display_t marker_type
Definition location.c:95
GObject * marker
Definition location.c:94
GtkEntry * search
Definition location.c:83
GList * callback_params
Definition location.c:85
GList * marker_points
Definition location.c:101
GModule *void * data
Definition lib.h:79
GtkWidget * widget
Definition lib.h:83
float lon1
Definition geo.h:41
float lat2
Definition geo.h:44
float lat1
Definition geo.h:42
float lon2
Definition geo.h:43
dt_map_box_t bbox
Definition location.c:677
dt_geo_map_display_t marker_type
Definition location.c:678
int32_t relevance
Definition location.c:673
_lib_location_type_t type
Definition location.c:674
gchar * dt_util_longitude_str(float longitude)
Definition utility.c:572
gchar * dt_util_latitude_str(float latitude)
Definition utility.c:554
void dt_view_map_center_on_location(const dt_view_manager_t *vm, gdouble lon, gdouble lat, gdouble zoom)
Definition view.c:1344
GObject * dt_view_map_add_marker(const dt_view_manager_t *vm, dt_geo_map_display_t type, GList *points)
Definition view.c:1368
void dt_view_map_center_on_bbox(const dt_view_manager_t *vm, gdouble lon1, gdouble lat1, gdouble lon2, gdouble lat2)
Definition view.c:1350
gboolean dt_view_map_remove_marker(const dt_view_manager_t *vm, dt_geo_map_display_t type, GObject *marker)
Definition view.c:1375
#define DT_GUI_BOX_SPACING
@ DT_UI_CONTAINER_PANEL_RIGHT_CENTER