aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias Andrée <m@maandree.se>2026-06-06 20:39:36 +0200
committerMattias Andrée <m@maandree.se>2026-06-06 20:39:36 +0200
commite61c74dba5dd3cd2a3e48aa1fc7ff2658e5cb6e1 (patch)
treeed75883a7c2527e2adc395b5e20c06d00632a5b7
parentSecond commit (diff)
downloadgcmap-e61c74dba5dd3cd2a3e48aa1fc7ff2658e5cb6e1.tar.gz
gcmap-e61c74dba5dd3cd2a3e48aa1fc7ff2658e5cb6e1.tar.bz2
gcmap-e61c74dba5dd3cd2a3e48aa1fc7ff2658e5cb6e1.tar.xz
misc
Signed-off-by: Mattias Andrée <m@maandree.se>
-rw-r--r--LICENSE2
-rw-r--r--Makefile7
-rw-r--r--README2
-rw-r--r--char-table.c44
-rw-r--r--char-table.h23
-rw-r--r--common.h27
-rw-r--r--config.mk4
-rw-r--r--gcmap.12
-rw-r--r--gcmap.c75
9 files changed, 134 insertions, 52 deletions
diff --git a/LICENSE b/LICENSE
index 0e6be1c..6c7f02b 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
ISC License
-© 2025 Mattias Andrée <m@maandree.se>
+© 2025, 2026 Mattias Andrée <m@maandree.se>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
diff --git a/Makefile b/Makefile
index 599dfdf..5eb2cab 100644
--- a/Makefile
+++ b/Makefile
@@ -4,9 +4,12 @@ CONFIGFILE = config.mk
include $(CONFIGFILE)
OBJ =\
- gcmap.o
+ gcmap.o\
+ char-table.o
-HDR =
+HDR =\
+ common.h\
+ char-table.h
all: gcmap
$(OBJ): $(HDR)
diff --git a/README b/README
index 7634d8a..5a09373 100644
--- a/README
+++ b/README
@@ -42,4 +42,4 @@ OPERANDS
No operands are supported.
SEE ALSO
- None.
+ cmap(1)
diff --git a/char-table.c b/char-table.c
new file mode 100644
index 0000000..da82544
--- /dev/null
+++ b/char-table.c
@@ -0,0 +1,44 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+G_DEFINE_TYPE(CharTable, gcmap_char_table, GTK_TYPE_DRAWING_AREA)
+
+
+static gboolean
+gcmap_char_table_expose(GtkWidget *widget, GdkEventExpose *event)
+{
+ cairo_t *cr = gdk_cairo_create(widget->window);
+
+ (void) event;
+
+ cairo_set_source_rgb(cr, 0.2f, 0.2f, 0.2f);
+ cairo_paint(cr);
+
+ cairo_set_source_rgb(cr, 1.0f, 1.0f, 1.0f);
+ cairo_move_to(cr, 10, 20);
+ cairo_show_text(cr, "Hello GTK+ 2");
+
+ cairo_destroy(cr);
+ return FALSE;
+}
+
+static void
+gcmap_char_table_init(CharTable *self)
+{
+ gtk_widget_set_size_request(GTK_WIDGET(self), 200, 100);
+}
+
+
+static void
+gcmap_char_table_class_init(CharTableClass *klass)
+{
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
+ widget_class->expose_event = gcmap_char_table_expose;
+}
+
+
+GtkWidget *
+gcmap_char_table_new(void)
+{
+ return g_object_new(GCMAP_TYPE_CHAR_TABLE, NULL);
+}
diff --git a/char-table.h b/char-table.h
new file mode 100644
index 0000000..0097e05
--- /dev/null
+++ b/char-table.h
@@ -0,0 +1,23 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+#define GCMAP_TYPE_CHAR_TABLE (gcmap_char_table_get_type())
+#define GCMAP_TYPE_CHAR(OBJ) (G_TYPE_CHECK_INSTANCE_CAST((OBJ), GCMAP_TYPE_CHAR_TABLE, CharTable))
+#define GCMAP_CHAR_TABLE_CLASS(CLASS) (G_TYPE_CHECK_CLASS_CAST((CLASS), GCMAP_TYPE_CHAR_TABLE, CharTableClass))
+#define IS_GCMAP_CHAR_TABLE(OBJ) (G_TYPE_CHECK_INSTANCE_TYPE((OBJ), GCMAP_TYPE_CHAR_TABLE))
+#define IS_GCMAP_CHAR_TABLE_CLASS(CLASS) (G_TYPE_CHECK_CLASS_TYPE((CLASS), GCMAP_TYPE_CHAR_TABLE))
+#define GCMAP_CHAR_TABLE_GET_CLASS(OBJ) (G_TYPE_INSTANCE_GET_CLASS((OBJ), GCMAP_TYPE_CHAR_TABLE, CharTableClass))
+
+
+typedef struct _CharTable {
+ GtkDrawingArea parent_instance;
+} CharTable;
+
+typedef struct _CharTableClass {
+ GtkDrawingAreaClass parent_class;
+} CharTableClass;
+
+
+GType gcmap_char_table_get_type(void);
+GtkWidget *gcmap_char_table_new(void);
diff --git a/common.h b/common.h
new file mode 100644
index 0000000..a7cd690
--- /dev/null
+++ b/common.h
@@ -0,0 +1,27 @@
+/* See LICENSE file for copyright and license details. */
+#ifndef COMMON_H_
+#define COMMON_H_
+
+#include <libsimple.h>
+#include <libsimple-arg.h>
+#include <libcmap.h>
+#if defined(__GNUC__)
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+# pragma GCC diagnostic ignored "-Wstrict-prototypes"
+#endif
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+#if defined(__GNUC__)
+# pragma GCC diagnostic pop
+#endif
+
+#if GTK_CHECK_VERSION(2, 12, 0)
+# define HAVE_ITEM_TOOLTIPS
+#endif
+
+#define COMMA ,
+
+#include "char-table.h"
+
+#endif
diff --git a/config.mk b/config.mk
index 0729912..ba12191 100644
--- a/config.mk
+++ b/config.mk
@@ -4,8 +4,8 @@ MANPREFIX = $(PREFIX)/share/man
CC = c99
CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_GNU_SOURCE
-CFLAGS =
-LDFLAGS = -lsimple -lcmap
+CFLAGS = $$(pkg-config --cflags pango)
+LDFLAGS = -lsimple -lcmap $$(pkg-config --libs pango)
CFLAGS_GTK2 = $$(pkg-config --cflags gtk+-2.0)
LDFLAGS_GTK2 = $$(pkg-config --libs gtk+-2.0)
diff --git a/gcmap.1 b/gcmap.1
index 864efb9..b873bde 100644
--- a/gcmap.1
+++ b/gcmap.1
@@ -64,4 +64,4 @@ is affected by environment variables that
affects its tooltik.
.SH SEE ALSO
-None.
+.BR cmap (1)
diff --git a/gcmap.c b/gcmap.c
index 36f0382..f03a704 100644
--- a/gcmap.c
+++ b/gcmap.c
@@ -1,28 +1,9 @@
/* See LICENSE file for copyright and license details. */
-#include <libsimple.h>
-#include <libsimple-arg.h>
-#include <libcmap.h>
-#if defined(__GNUC__)
-# pragma GCC diagnostic push
-# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-# pragma GCC diagnostic ignored "-Wstrict-prototypes"
-#endif
-#include <gtk/gtk.h>
-#include <gdk/gdkkeysyms.h>
-#if defined(__GNUC__)
-# pragma GCC diagnostic pop
-#endif
+#include "common.h"
USAGE("[-f font-family] [-s [font-size][/[[min]-[max]]]] [-B | -S] [-bi]");
-#if GTK_CHECK_VERSION(2, 12, 0)
-# define HAVE_ITEM_TOOLTIPS
-#endif
-
-
-#define COMMA ,
-
#define DEFAULT_LISTING_TYPE "script"
#define LIST_LISTINGS(X, D)\
X(BY_SCRIPT, "By _script", DEFAULT_LISTING_TYPE, by_script_selected, populate_scripts, GDK_s) D\
@@ -37,6 +18,9 @@ enum listing {
#define NLISTINGS_X(...) (size_t)1
#define NLISTINGS (LIST_LISTINGS(NLISTINGS_X, +))
+
+static const struct libcmap_block all_block = {.name = "All", .range = LIBCMAP_UNIVERSE_RANGE};
+
static unsigned int min_font_size = 4;
static unsigned int default_font_size = 22;
static unsigned int max_font_size = 500;
@@ -139,7 +123,6 @@ grouplist_query_tooltip(GtkWidget *widget, int x, int y, int keyboard_mode,
static char *
script_tooltip(const struct libcmap_script *script)
{
- unsigned long int low, high;
size_t i, len, off = 0;
int r;
char *ret;
@@ -149,9 +132,7 @@ script_tooltip(const struct libcmap_script *script)
len = strlen(script->name) + 1U;
for (i = 0; i < script->nranges; i++) {
- low = (unsigned long int)script->ranges[i].first;
- high = (unsigned long int)script->ranges[i].last;
- r = snprintf(NULL, 0, "U+%04lX–U+%04lX", low, high);
+ r = libcmap_sprint_range(NULL, &script->ranges[i], NULL);
if (r < 0)
return NULL;
len += (size_t)r + 2U;
@@ -161,14 +142,15 @@ script_tooltip(const struct libcmap_script *script)
if (!ret)
return NULL;
- stpcpy(ret, script->name);
- off = strlen(script->name);
+ off = (size_t)(stpcpy(ret, script->name) - ret);
ret[off++] = ' ';
ret[off++] = '(';
for (i = 0; i < script->nranges; i++) {
- low = (unsigned long int)script->ranges[i].first;
- high = (unsigned long int)script->ranges[i].last;
- r = sprintf(&ret[off], "%sU+%04lX–U+%04lX", i ? ", " : "", low, high);
+ if (i) {
+ ret[off++] = ',';
+ ret[off++] = ' ';
+ }
+ r = libcmap_sprint_range(&ret[off], &script->ranges[i], NULL);
if (r < 0)
return NULL;
off += (size_t)r;
@@ -185,22 +167,25 @@ script_tooltip(const struct libcmap_script *script)
static char *
block_tooltip(const struct libcmap_block *block)
{
- unsigned long int low = (unsigned long int)block->range.first;
- unsigned long int high = (unsigned long int)block->range.last;
int len, r;
- char *ret;
+ char *ret, *p;
+ size_t size;
- len = snprintf(NULL, 0, "%s (U+%04lX–U+%04lX)", block->name, low, high);
+ size = strlen(block->name) + sizeof(" ()");
+ len = libcmap_sprint_range(NULL, &block->range, NULL);
if (len < 0)
return NULL;
+ size += (size_t)len;
- ret = malloc((size_t)len + 1U);
+ ret = malloc(size);
if (!ret)
return NULL;
- r = sprintf(ret, "%s (U+%04lX–U+%04lX)", block->name, low, high);
+ p = stpcpy(stpcpy(ret, block->name), " (");
+ r = libcmap_sprint_range(p, &block->range, NULL);
if (r < 0 || r > len)
abort();
+ stpcpy(&p[r], ")");
return ret;
}
@@ -227,7 +212,7 @@ populate_scripts(GtkListStore *store)
if (!group_tooltips[BY_SCRIPT]) {
ngroup_tooltips[BY_SCRIPT] = n + 1U;
group_tooltips[BY_SCRIPT] = calloc(ngroup_tooltips[BY_SCRIPT], sizeof(**group_tooltips));
- group_tooltips[BY_SCRIPT][0] = "All (U+0000–U+10FFFF)";
+ group_tooltips[BY_SCRIPT][0] = block_tooltip(&all_block);
for (i = 0; i < n; i++) {
if (!strcmp(list[i].name, "Unknown"))
group_tooltips[BY_SCRIPT][i + 1U] = "Unknown (Codepoints not assigned any script)";
@@ -261,7 +246,7 @@ populate_blocks(GtkListStore *store)
if (!group_tooltips[BY_BLOCK]) {
ngroup_tooltips[BY_BLOCK] = n + 2U;
group_tooltips[BY_BLOCK] = calloc(ngroup_tooltips[BY_BLOCK], sizeof(**group_tooltips));
- group_tooltips[BY_BLOCK][0] = "All (U+0000–U+10FFFF)";
+ group_tooltips[BY_BLOCK][0] = block_tooltip(&all_block);
group_tooltips[BY_BLOCK][n + 1U] = "No Block (Codepoints not assigned any block)";
for (i = 0; i < n; i++)
group_tooltips[BY_BLOCK][i + 1U] = block_tooltip(&list[i]);
@@ -299,7 +284,7 @@ fontcombo_changed(GtkComboBox *combo, void *user_data) /* TODO */
(void) user_data;
if (!gtk_combo_box_get_active_iter(combo, &iter))
return;
- gtk_tree_model_get(GTK_TREE_MODEL(fontcombo_store), &iter,0, &family, -1);
+ gtk_tree_model_get(GTK_TREE_MODEL(fontcombo_store), &iter, 0, &family, -1);
if (!family)
return;
}
@@ -764,7 +749,7 @@ create_window(void)
gtk_combo_box_set_focus_on_click(GTK_COMBO_BOX(fontcombo), FALSE);
gtk_box_pack_start(GTK_BOX(hbox), fontcombo, FALSE, FALSE, 0);
gtk_combo_box_set_active(GTK_COMBO_BOX(fontcombo), -1);
- g_signal_connect(fontcombo, "changed", G_CALLBACK(fontcombo_changed), NULL);
+ g_signal_connect(fontcombo, "changed", G_CALLBACK(&fontcombo_changed), NULL);
accessible = gtk_widget_get_accessible(fontcombo);
atk_object_set_name(accessible, "Font family");
@@ -822,7 +807,7 @@ create_window(void)
scrolled = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_NONE);
- gtk_container_add(GTK_CONTAINER(scrolled), gtk_label_new("TODO"));
+ gtk_container_add(GTK_CONTAINER(scrolled), gcmap_char_table_new());
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled, gtk_label_new_with_mnemonic("Character _table"));
#ifdef TODO
@@ -1017,20 +1002,20 @@ main(int argc, char *argv[])
gtk_init(&xargc, &xargv);
theme = gtk_icon_theme_get_default();
- if (!gtk_icon_theme_has_icon(theme, icon = "apps/gcmap") ||
- !gtk_icon_theme_has_icon(theme, icon = "gcmap") ||
- !gtk_icon_theme_has_icon(theme, icon = "apps/accessories-character-map") ||
+ if (!gtk_icon_theme_has_icon(theme, icon = "apps/gcmap") &&
+ !gtk_icon_theme_has_icon(theme, icon = "gcmap") &&
+ !gtk_icon_theme_has_icon(theme, icon = "apps/accessories-character-map") &&
!gtk_icon_theme_has_icon(theme, icon = "accessories-character-map"))
icon = "gcmap";
gtk_window_set_default_icon_name(icon);
create_window();
gtk_window_set_icon_name(GTK_WINDOW(window), icon);
+ gtk_window_set_wmclass(GTK_WINDOW(window), "gcmap", "gcmap");
+ gtk_window_set_role(GTK_WINDOW(window), "gcmap");
if (gtk_combo_box_get_active(GTK_COMBO_BOX(listcombo)) != (int)listing)
gtk_combo_box_set_active(GTK_COMBO_BOX(listcombo), (int)listing);
- if (gtk_combo_box_get_active(GTK_COMBO_BOX(listcombo)) != (int)listing)
- gtk_combo_box_set_active(GTK_COMBO_BOX(listcombo), (int)listing);
if (use_bold)
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(bold), TRUE);
if (use_italic)