Skip to content

Instantly share code, notes, and snippets.

@Miqueas
Last active March 17, 2021 02:03
Show Gist options
  • Save Miqueas/c52a7f6684036030572a66d1f58ba574 to your computer and use it in GitHub Desktop.
Save Miqueas/c52a7f6684036030572a66d1f58ba574 to your computer and use it in GitHub Desktop.
[C + Gtk 3] Generic password window
#include <gtk/gtk.h>
GtkWidget *user, *pass, *confirm, *clear, *check;
GRegex *patt;
GtkWidget* build_grid() {
GtkWidget *label;
GtkWidget *grid = g_object_new(
GTK_TYPE_GRID,
"visible", TRUE,
"column-spacing", 6,
"row-spacing", 6,
"halign", GTK_ALIGN_CENTER,
"valign", GTK_ALIGN_CENTER,
NULL
);
user = g_object_new(GTK_TYPE_ENTRY, "visible", TRUE, NULL);
pass = g_object_new(GTK_TYPE_ENTRY, "visible", TRUE, "visibility", FALSE, NULL);
confirm = g_object_new(GTK_TYPE_ENTRY, "visible", TRUE, "visibility", FALSE, NULL);
gtk_entry_set_input_purpose(GTK_ENTRY(pass), GTK_INPUT_PURPOSE_PASSWORD);
gtk_entry_set_input_purpose(GTK_ENTRY(confirm), GTK_INPUT_PURPOSE_PASSWORD);
label = g_object_new(
GTK_TYPE_LABEL,
"label", "Usuario",
"visible", TRUE,
"xalign", 1.0,
NULL
);
gtk_grid_attach(GTK_GRID(grid), label, 0, 0, 1, 1);
gtk_grid_attach(GTK_GRID(grid), user, 1, 0, 1, 1);
label = g_object_new(
GTK_TYPE_LABEL,
"label", "Contraseña",
"visible", TRUE,
"xalign", 1.0,
NULL
);
gtk_grid_attach(GTK_GRID(grid), label, 0, 1, 1, 1);
gtk_grid_attach(GTK_GRID(grid), pass, 1, 1, 1, 1);
label = g_object_new(
GTK_TYPE_LABEL,
"label", "Repita la contraseña",
"visible", TRUE,
"xalign", 1.0,
NULL
);
gtk_grid_attach(GTK_GRID(grid), label, 0, 2, 1, 1);
gtk_grid_attach(GTK_GRID(grid), confirm, 1, 2, 1, 1);
check = g_object_new(
GTK_TYPE_CHECK_BUTTON,
"label", "Mostrar contraseña",
"visible", TRUE,
NULL
);
clear = g_object_new(
GTK_TYPE_BUTTON,
"label", "Limpiar",
"visible", TRUE,
"halign", GTK_ALIGN_END,
NULL
);
gtk_grid_attach(GTK_GRID(grid), check, 1, 3, 1, 1);
gtk_grid_attach(GTK_GRID(grid), clear, 1, 4, 1, 1);
return grid;
}
gboolean user_input(GtkWidget *self, GdkEvent *ev, gpointer data) {
const char *val = gtk_entry_get_text(GTK_ENTRY(self));
if ( g_regex_match(patt, val, 0, NULL) ) {
gtk_entry_set_icon_from_icon_name(
GTK_ENTRY(self),
GTK_ENTRY_ICON_SECONDARY, "process-completed-symbolic"
);
} else {
gtk_entry_set_icon_from_icon_name(
GTK_ENTRY(self),
GTK_ENTRY_ICON_SECONDARY, "process-error-symbolic"
);
}
return FALSE;
}
gboolean confirm_input(GtkWidget *self, GdkEvent *ev, gpointer data) {
const char *original = gtk_entry_get_text(GTK_ENTRY(pass));
const char *confirmation = gtk_entry_get_text(GTK_ENTRY(self));
if ( g_str_equal(confirmation, original) ) {
gtk_entry_set_icon_from_icon_name(
GTK_ENTRY(self),
GTK_ENTRY_ICON_SECONDARY, "process-completed-symbolic"
);
} else {
gtk_entry_set_icon_from_icon_name(
GTK_ENTRY(self),
GTK_ENTRY_ICON_SECONDARY, "process-error-symbolic"
);
}
return FALSE;
}
void check_toggled(GtkWidget *self, gpointer data) {
gboolean active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(self));
if (active) {
gtk_entry_set_visibility(GTK_ENTRY(pass), TRUE);
gtk_entry_set_visibility(GTK_ENTRY(confirm), TRUE);
} else {
gtk_entry_set_visibility(GTK_ENTRY(pass), FALSE);
gtk_entry_set_visibility(GTK_ENTRY(confirm), FALSE);
}
}
void clear_clicked(GtkWidget *self, gpointer data) {
gtk_entry_set_text(GTK_ENTRY(user), "");
gtk_entry_set_text(GTK_ENTRY(pass), "");
gtk_entry_set_text(GTK_ENTRY(confirm), "");
}
void app_activate(GtkApplication *self, gpointer data) {
GtkWidget *win = g_object_new(
GTK_TYPE_APPLICATION_WINDOW,
"application", self,
"border-width", 10,
NULL
);
gtk_container_add(GTK_CONTAINER(win), build_grid());
patt = g_regex_new("^([a-z]+[a-z0-9]*)$", 0, 0, NULL);
g_signal_connect(user, "notify::text", G_CALLBACK(user_input), NULL);
g_signal_connect(confirm, "notify::text", G_CALLBACK(confirm_input), NULL);
g_signal_connect(check, "toggled", G_CALLBACK(check_toggled), NULL);
g_signal_connect(clear, "clicked", G_CALLBACK(clear_clicked), NULL);
gtk_window_present(GTK_WINDOW(win));
}
int main(int argc, char **argv) {
GtkApplication *app = gtk_application_new("org.example.gtk.password", G_APPLICATION_FLAGS_NONE);
g_signal_connect(app, "activate", G_CALLBACK(app_activate), NULL);
int res = g_application_run(G_APPLICATION(app), argc, argv);
g_object_unref(app);
g_clear_pointer(&patt, g_regex_unref);
return res;
}
@nyx-lyb3ra
Copy link

https://gist.github.com/Miqueas/c52a7f6684036030572a66d1f58ba574#file-password-c-L113-L114

GtkWidget *win = g_object_new (GTK_TYPE_APPLICATION_WINDOW,
                               "application", self,
                               "border-width", 10,
                               NULL);

https://gist.github.com/Miqueas/c52a7f6684036030572a66d1f58ba574#file-password-c-L116

Todos los GtkWidgets heredan de GInitiallyUnowned, evitandote la necesidad de desreferenciarlos manualmente si los empacas dentro de otro GtkWidget, por lo que incluso podrías cambiar tu código a algo como esto:

gtk_container_add (GTK_CONTAINER (win), build_grid ());

https://gist.github.com/Miqueas/c52a7f6684036030572a66d1f58ba574#file-password-c-L119

Nota: Vala tiene soporte de sintaxis para GRegex 😉

Regex patt = /^([a-z]+[a-z0-9]*)$/;

https://gist.github.com/Miqueas/c52a7f6684036030572a66d1f58ba574#file-password-c-L121-L122

Usa la señal ::notify en lugar de ::key-release-event para obtener un evento cada vez que la propiedad :text cambia, en lugar de obtener uno cada vez que el usuario suelta una tecla

g_signal_connect (user, "notify::text", G_CALLBACK (user_input), NULL);
g_signal_connect (confirm, "notify::text", G_CALLBACK (confirm_input), NULL);

https://gist.github.com/Miqueas/c52a7f6684036030572a66d1f58ba574#file-password-c-L3-L6

Es preferible trabajar con GtkWidget en lugar de clases más específicas

GtkWidget *user, *pass, *confirm, *clear, *check;
GRegex *patt;

https://gist.github.com/Miqueas/c52a7f6684036030572a66d1f58ba574#file-password-c-L8

Es más idiomático que devuelvas un GtkWidget* en lugar de un GtkGrid*

https://gist.github.com/Miqueas/c52a7f6684036030572a66d1f58ba574#file-password-c-L11

GtkWidget *grid = g_object_new (GTK_TYPE_GRID,
                                "visible", TRUE,
                                "column-spacing", 6,
                                "row-spacing", 6,
                                "halign", GTK_ALIGN_CENTER,
                                "valign", GTK_ALIGN_CENTER,
                                NULL);

https://gist.github.com/Miqueas/c52a7f6684036030572a66d1f58ba574#file-password-c-L21-L27

user    = g_object_new (GTK_TYPE_ENTRY, "visible", TRUE, NULL);
pass    = g_object_new (GTK_TYPE_ENTRY, "visible", TRUE, "visibility", FALSE, NULL);
confirm = g_object_new (GTK_TYPE_ENTRY, "visible", TRUE, "visibility", FALSE, NULL);

https://gist.github.com/Miqueas/c52a7f6684036030572a66d1f58ba574#file-password-c-L26-L27

Mira también de informar a los OSK de que esas entradas son para contraseñas mediante la propiedad :input-purpose

gtk_entry_set_input_purpose (GTK_ENTRY (pass), GTK_INPUT_PURPOSE_PASSWORD);

https://gist.github.com/Miqueas/c52a7f6684036030572a66d1f58ba574#file-password-c-L29-L31
https://gist.github.com/Miqueas/c52a7f6684036030572a66d1f58ba574#file-password-c-L36-L38
https://gist.github.com/Miqueas/c52a7f6684036030572a66d1f58ba574#file-password-c-L43-L45

GtkWidget *label = g_object_new (GTK_TYPE_LABEL,
                                 "label", "Usuario",
                                 "visible", TRUE,
                                 "xalign", 1,
                                 NULL);

https://gist.github.com/Miqueas/c52a7f6684036030572a66d1f58ba574#file-password-c-L50-L51

check = g_object_new (GTK_TYPE_CHECK_BUTTON,
                      "label", "Mostrar contraseña",
                      "visible", TRUE,
                      NULL);

https://gist.github.com/Miqueas/c52a7f6684036030572a66d1f58ba574#file-password-c-L53-L58

clear = g_object_new (GTK_TYPE_BUTTON,
                      "label", "Limpiar",
                      "visible", TRUE,
                      "halign", GTK_ALIGN_END,
                      NULL);

https://gist.github.com/Miqueas/c52a7f6684036030572a66d1f58ba574#file-password-c-L67-L68
https://gist.github.com/Miqueas/c52a7f6684036030572a66d1f58ba574#file-password-c-L80-L82

char* val = gtk_entry_get_text (GTK_ENTRY (self));

https://gist.github.com/Miqueas/c52a7f6684036030572a66d1f58ba574#file-password-c-L94-L95

gboolean active = gtk_toggle_button_get_active (self);

https://gist.github.com/Miqueas/c52a7f6684036030572a66d1f58ba574#file-password-c-L97-L103

if (active) {
  gtk_entry_set_visibility (GTK_ENTRY (pass), TRUE);
  gtk_entry_set_visibility (GTK_ENTRY (confirm), TRUE);
} else {
  gtk_entry_set_visibility (GTK_ENTRY (pass), FALSE);
  gtk_entry_set_visibility (GTK_ENTRY (confirm), FALSE);
}

https://gist.github.com/Miqueas/c52a7f6684036030572a66d1f58ba574#file-password-c-L107-L109

gtk_entry_set_text (GTK_ENTRY (user), "");
gtk_entry_set_text (GTK_ENTRY (pass), "");
gtk_entry_set_text (GTK_ENTRY (confirm), "");

@nyx-lyb3ra
Copy link

Ah, y casi olvidaba: ese GRegex no se va a liberar solo

g_clear_pointer (&patt, g_regex_unref);

Lo haces antes del return res;

@Miqueas
Copy link
Author

Miqueas commented Mar 17, 2021

@nahuelwexd corregido! Gracias por comentar :P

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment