@Dafyd: Yep, Haskell c’est bien sympa comme langage fonctionnel. Tu peux partir là-dessus si tu veux 

if account && account.owner && account.owner.address
end
account&.owner&.address
Petite trouvaille du soir… en utilisant l'excellent RuboCop qui m'a gratifié du message suivant :lib/ylem/helper/subprocess.rb:44:33: C: Style/SafeNavigation: Use safe navigation (&.) instead of checking if an object exists before calling the method.
.map { |source, thread| thread.join if thread }
à utiliser sans modérationHP a écritThe Safe Navigation Operator (&.) in Ruby
http://mitrev.net/ruby/2015/11/13/the-operator-in-ruby/
À priori, ce que tu utilises c’est le Digest access authentication de HTTP, du coup Wikipédia est un bon point de départ.Elzen a écritSi quelqu'un a de la bonne doc' sur la façon dont est gérée l'authentification http des deux côté, ça m'intéresse.
En effet, ça aurait été une solution possible mais du coup ça demande 2 requêtes par page (un GET qui se prend un 401, puis un GET avec les informations), c’est peut-être pour ça que ça n’a pas été retenu.Elzen a écritÇa n'a rien de surprenant, en effet; mais je pensais naïvement que le navigateur attendait de recevoir la demande d'authentification de la part du serveur pour renvoyer les infos (ce qui n'aurait pas nécessité de session non plus, le serveur envoyant la demande systématiquement tant qu'il ne reçoit pas ce dont il a besoin).
Tu peux détailler?Elzen a écrit(Sinon, pour l'autre problème, j'ai trouvé une parade temporaire, faute de mieux: une GtkSocket dans le panel en GTK3, et la barre d'onglets dans un GtkPlug géré par du code PyGTK. Pas forcément ce qu'il y a de plus léger, mais d'un autre côté, ça permet une certaine souplesse)
Yep, en effet.grim7reaper a écritEn effet, ça aurait été une solution possible mais du coup ça demande 2 requêtes par page (un GET qui se prend un 401, puis un GET avec les informations), c’est peut-être pour ça que ça n’a pas été retenu.
Dans l'usage de base, c'est relativement simple; après, naturellement, je m'en sers bizarrementgrim7reaper a écritTu peux détailler?
Je connaissais pas ce système de GtkSocket/GtkPlug.
J'ai réussi \o/grim7reaper a écritSi je comprends bien ce que tu veux faire, tu veux voir seulement [page 1][page 2][page 3] sur cet exemple?
Est-ce que tu dois vraiment passer par un Notebook?
Je connais pas les détails mais tu pourrais pas simplement avoir une fenêtre avec des boutons/whatever empilé horizontalement?
style = gtk.StyleContext()
if active: # Styler comme l'onglet actif.
style.set_state(gtk.StateFlags.CHECKED)
wpath = gtk.WidgetPath()
for i, name in enumerate(["notebook", "header", "tabs", "tab"]):
wpath.append_type(gtk.Notebook) # Sans un append_ avant le iter_set_, ça segfault.
wpath.iter_set_object_name(i, name)
wpath.iter_add_class(1, edge) # "top", "left", "right" ou "bottom"
style.set_path(wpath)
Et ensuite, on peut tranquillement peindre ça, et ça a bien la tête demandée.window.shape_combine_region(cairo.Region([cairo.RectangleInt(x1, y1, w1, h1), cairo.RectangleInt(x2, y2, w2, h2), …])
mais bon, du coup je n'en ai plus besoin pour ça, donc ça va.)wid = wnck.screen_get_default().get_background_pixmap()
if wid > 0L:
display = gtk.gdk.display_get_default()
pixmap = gtk.gdk.pixmap_foreign_new_for_display(display, wid)
pixmap.set_colormap(gtk.gdk.screen_get_default().get_rgb_colormap())
# S'il y a besoin de convertir le pixmap en pixbuf…
w, h = pixmap.get_size()
pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, w, h)
pixbuf.get_from_drawable(pixmap, gtk.gdk.colormap_get_system(), 0, 0, 0, 0, w, h)
La fonction get_background_pixmap() existe encore dans WNCK, donc j'arrive encore à accéder à l'id de la fenêtre X correspondante, mais c'est ensuite que ça se gâte :Eut-ce été si simple que ça que ça n'aurait pas été drôle :rolleyes:Elzen a écrit J'ai réussi \o/
[…]
Il suffit donc ensuite de peindre ça sur le fond des différents widgets censés ressembler à des onglets, et tout marche.
Il faut encore que je joue un peu avec pour être sûr, mais je crois bien que ce truc est réglé
#ifndef HEADER_LIST
#define HEADER_LIST
#include <stdlib.h>
typedef struct list_priv_t* list_priv_t;
typedef struct list_t* list_t;
struct list_t {
list_priv_t priv;
size_t (*length)(list_t list);
void (*add)(list_t list, void *el);
void* (*get)(list_t list, size_t index);
void (*remove_at)(list_t list, size_t index);
void (*remove)(list_t list, void *el);
};
list_t list_new(void);
void list_del(list_t *list);
void list_del_with_free(list_t *list);
#endif
list.c
#include "utils/list.h"
struct list_priv_t {
size_t length;
void ** objs;
};
static void rearrange(list_t list) {
size_t i, j;
for (i = 0; i < list->priv->length; i++) {
if (list->priv->objs[i] == NULL) {
for (j = i; j < list->priv->length - 1; j++) {
list->priv->objs[j] = list->priv->objs[j + 1];
}
list->priv->length--;
list->priv->objs = realloc(list->priv->objs, list->priv->length * sizeof(*(list->priv->objs)));
i--;
}
}
}
static size_t length_impl(list_t list) {
return list->priv->length;
}
static void add_impl(list_t list, void *el) {
list->priv->objs = realloc(list->priv->objs, (list->priv->length + 1) * sizeof(el));
list->priv->objs[list->priv->length] = el;
list->priv->length++;
}
static void* get_impl(list_t list, size_t index) {
if (index >= list->priv->length) {
return NULL;
}
else {
return list->priv->objs[index];
}
}
static void remove_at_impl(list_t list, size_t index) {
if (index < list->priv->length) {
list->priv->objs[index] = NULL;
rearrange(list);
}
}
static void remove_impl(list_t list, void *el) {
size_t i;
for (i = 0; i < list->priv->length; i++) {
if (list->priv->objs[i] == el) {
list->priv->objs[i] = NULL;
rearrange(list);
}
}
}
list_t list_new(void) {
list_t list = malloc(sizeof(*list));
list->priv = malloc(sizeof(*(list->priv)));
list->priv->length = 0;
list->priv->objs = NULL;
list->length = &length_impl;
list->add = &add_impl;
list->get = &get_impl;
list->remove_at = &remove_at_impl;
list->remove = &remove_impl;
return list;
}
void list_del(list_t *list) {
if (list && *list) {
if ((*list)->priv) {
if ((*list)->priv->objs) {
free((*list)->priv->objs);
}
free((*list)->priv);
}
free(*list);
*list = NULL;
}
}
void list_del_with_free(list_t *list) {
size_t i;
for (i = 0; i < (*list)->length(*list); i++) {
free((*list)->get((*list), i));
}
list_del(list);
}
str.h
#ifndef HEADER_STR
#define HEADER_STR
#include <stdlib.h>
#include <string.h>
#include "utils/list.h"
typedef struct str_priv_t* str_priv_t;
typedef struct str_t* str_t;
struct str_t {
str_priv_t priv;
char* (*cstr)(str_t str);
void (*set)(str_t str, char* src);
list_t (*split)(str_t str, str_t delimiter);
};
str_t str_new(void);
str_t str_new_from(char* cstr);
void str_del(str_t *str);
#endif
str.c
#include "utils/str.h"
struct str_priv_t {
char* str;
};
static char* cstr_impl(str_t str) {
return str->priv->str;
}
static void set_impl(str_t str, char* src) {
str->priv->str = realloc(str->priv->str, strlen(src) + 1);
strcpy(str->priv->str, src);
}
static list_t split_impl(str_t str, str_t delimiter) {
char *begin, *end, *buf = NULL;
size_t length;
list_t list = list_new();
begin = str->cstr(str);
while ((end = strstr(begin, delimiter->cstr(delimiter)))) {
length = end - begin;
buf = calloc(length + 1, 1);
strncpy(buf, begin, length);
list->add(list, (void*)str_new_from(buf));
free(buf);
begin = end + 1;
}
list->add(list, (void*)str_new_from(begin));
return list;
}
str_t str_new(void) {
str_t str = malloc(sizeof(*str));
str->priv = malloc(sizeof(*(str->priv)));
str->priv->str = malloc(1);
strcpy(str->priv->str, "");
str->cstr = &cstr_impl;
str->set = &set_impl;
str->split = &split_impl;
return str;
}
str_t str_new_from(char* cstr) {
str_t str = str_new();
str->set(str, cstr);
return str;
}
void str_del(str_t *str) {
if (str && *str) {
if ((*str)->priv) {
if ((*str)->priv->str) {
free((*str)->priv->str);
}
free((*str)->priv);
}
free(*str);
*str = NULL;
}
}
Et le petit main qui utilise tout cela pour test:
#include <stdlib.h>
#include <stdio.h>
#include "utils/str.h"
int main(void) {
size_t i;
str_t str, delimiter;
list_t list;
str = str_new();
delimiter = str_new();
str->set(str, "toto:tutu:lol");
delimiter->set(delimiter, ":");
list = str->split(str, delimiter);
printf("[");
for (i = 0; i < list->length(list); i++) {
void *el = list->get(list, i);
if (el) {
printf("%s", ((str_t)el)->cstr((str_t)el));
}
else {
printf("NULL");
}
if (i < list->length(list) - 1) {
printf(", ");
}
}
puts("]");
str_del(&str);
str_del(&delimiter);
list_del_with_free(&list);
return EXIT_SUCCESS;
}
Valgrind me sort ceci :
==4338== Memcheck, a memory error detector
==4338== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==4338== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==4338== Command: ./jeudemerdequiserajamaisfinicommedhab
==4338==
[toto, tutu, lol]
==4338==
==4338== HEAP SUMMARY:
==4338== in use at exit: 38 bytes in 6 blocks
==4338== total heap usage: 28 allocs, 22 frees, 1,381 bytes allocated
==4338==
==4338== 12 (8 direct, 4 indirect) bytes in 1 blocks are definitely lost in loss record 3 of 4
==4338== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4338== by 0x1093CA: str_new (str.c:44)
==4338== by 0x10943E: str_new_from (str.c:56)
==4338== by 0x10938F: split_impl (str.c:37)
==4338== by 0x108CEA: main (main.c:18)
==4338==
==4338== 26 (16 direct, 10 indirect) bytes in 2 blocks are definitely lost in loss record 4 of 4
==4338== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4338== by 0x1093CA: str_new (str.c:44)
==4338== by 0x10943E: str_new_from (str.c:56)
==4338== by 0x109322: split_impl (str.c:30)
==4338== by 0x108CEA: main (main.c:18)
==4338==
==4338== LEAK SUMMARY:
==4338== definitely lost: 24 bytes in 3 blocks
==4338== indirectly lost: 14 bytes in 3 blocks
==4338== possibly lost: 0 bytes in 0 blocks
==4338== still reachable: 0 bytes in 0 blocks
==4338== suppressed: 0 bytes in 0 blocks
==4338==
==4338== For counts of detected and suppressed errors, rerun with: -v
==4338== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
Donc apparemment mon list_del_with_free ne fait pas le boulot correctement, mais je ne comprends pas pourquoi...==9447== 4 bytes in 1 blocks are indirectly lost in loss record 1 of 4
==9447== at 0x4C2F0FF: realloc (vg_replace_malloc.c:785)
==9447== by 0x108F7F: set_impl (str.c:14)
==9447== by 0x10916A: str_new_from (str.c:57)
==9447== by 0x10909F: split_impl (str.c:37)
==9447== by 0x108E21: main (main.c:18)
==9447==
==9447== 10 bytes in 2 blocks are indirectly lost in loss record 2 of 4
==9447== at 0x4C2F0FF: realloc (vg_replace_malloc.c:785)
==9447== by 0x108F7F: set_impl (str.c:14)
==9447== by 0x10916A: str_new_from (str.c:57)
==9447== by 0x109032: split_impl (str.c:30)
==9447== by 0x108E21: main (main.c:18)
==9447==
==9447== 12 (8 direct, 4 indirect) bytes in 1 blocks are definitely lost in loss record 3 of 4
==9447== at 0x4C2CEDF: malloc (vg_replace_malloc.c:299)
==9447== by 0x1090DA: str_new (str.c:44)
==9447== by 0x10914E: str_new_from (str.c:56)
==9447== by 0x10909F: split_impl (str.c:37)
==9447== by 0x108E21: main (main.c:18)
==9447==
==9447== 26 (16 direct, 10 indirect) bytes in 2 blocks are definitely lost in loss record 4 of 4
==9447== at 0x4C2CEDF: malloc (vg_replace_malloc.c:299)
==9447== by 0x1090DA: str_new (str.c:44)
==9447== by 0x10914E: str_new_from (str.c:56)
==9447== by 0x109032: split_impl (str.c:30)
==9447== by 0x108E21: main (main.c:18)
Donc en gros la mémoire perdue vient de set_impl (qui alloue priv->str) et de la ligne 44 de str_new (qui alloue priv).#include <stdlib.h>
#include <stdio.h>
typedef struct base_t* base_t;
typedef struct derivated_t* derivated_t;
struct base_t {
int a;
};
struct derivated_t {
base_t base;
};
int main(void) {
derivated_t derivated = malloc(sizeof(*derivated));
derivated->base = malloc(sizeof(*(derivated->base)));
((base_t)derivated)->a = 45;
printf("%d\n", ((base_t)derivated)->a);
return EXIT_SUCCESS;
}
Tu en penses quoi ?