diff --git a/src/Makefile b/src/Makefile
index 56e4f69..be8cddc 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1,5 +1,5 @@
-CFLAGS = -Wall -Wextra `pkg-config --cflags gtk+-2.0` -g
-LIBS = `pkg-config --libs gtk+-2.0`
+CFLAGS = -Wall -Wextra `pkg-config --cflags gtk4` -g
+LIBS = `pkg-config --libs gtk4`
 
 SRCS = main.c gui.c chip_atmel_atmega32.c button.c led.c poti.c seg7.c sig_std_logic.c
 HDRS = gui.h chip_atmel_atmega32.h button.h led.h poti.h seg7.h sig_std_logic.h
diff --git a/src/button.c b/src/button.c
index 6987d9b..a29723a 100644
--- a/src/button.c
+++ b/src/button.c
@@ -1,5 +1,4 @@
 #include <assert.h>
-#include <stdio.h>
 #include <stdlib.h>
 #include <gtk/gtk.h>
 
@@ -13,30 +12,30 @@ struct cpssp {
 	struct sig_std_logic *port;
 };
 
-static gboolean
-button_pressed(GtkWidget *w, GdkEventButton *event, gpointer _cpssp)
+static void
+button_pressed(GtkGestureClick *gesture, int n_press, double x, double y, gpointer _cpssp)
 {
 	struct cpssp *cpssp = _cpssp;
 
-	(void) w;
-	(void) event;
+	(void) gesture;
+	(void) n_press;
+	(void) x;
+	(void) y;
 
 	sig_std_logic_set(cpssp->port, cpssp, SIG_STD_LOGIC_0);
-
-	return FALSE;
 }
 
-static gboolean
-button_released(GtkWidget *w, GdkEventButton *event, gpointer _cpssp)
+static void
+button_released(GtkGestureClick *gesture, int n_press, double x, double y, gpointer _cpssp)
 {
 	struct cpssp *cpssp = _cpssp;
 
-	(void) w;
-	(void) event;
+	(void) gesture;
+	(void) n_press;
+	(void) x;
+	(void) y;
 
 	sig_std_logic_set(cpssp->port, cpssp, SIG_STD_LOGIC_Z);
-
-	return FALSE;
 }
 
 void *
@@ -48,12 +47,16 @@ button_create(const char *name, struct sig_std_logic *port)
 	assert(cpssp);
 
 	cpssp->gui_button = gtk_button_new();
-	g_signal_connect(cpssp->gui_button, "button-press-event",
-		      G_CALLBACK(button_pressed), (gpointer) cpssp);
-	g_signal_connect(cpssp->gui_button, "button-release-event",
-		      G_CALLBACK(button_released), (gpointer) cpssp);
 
-	gtk_widget_show(cpssp->gui_button);
+	GtkGesture *gesture = gtk_gesture_click_new();
+	gtk_event_controller_set_propagation_phase(GTK_EVENT_CONTROLLER(gesture), GTK_PHASE_CAPTURE);
+
+	g_signal_connect(gesture, "pressed",
+			G_CALLBACK(button_pressed), cpssp);
+	g_signal_connect(gesture, "released",
+			G_CALLBACK(button_released), cpssp);
+
+	gtk_widget_add_controller(cpssp->gui_button, GTK_EVENT_CONTROLLER(gesture));
 
 	gui_add(name, cpssp->gui_button);
 
diff --git a/src/gui.c b/src/gui.c
index 9170fa0..76e45f7 100644
--- a/src/gui.c
+++ b/src/gui.c
@@ -1,4 +1,3 @@
-#include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <gtk/gtk.h>
@@ -9,8 +8,8 @@ extern int end;
 
 static GtkWidget *window;
 static GtkWidget *hbox;
-static GMainContext *main_context;
 
+static GMainLoop *loop;
 
 static gboolean
 gui_delete(GtkWidget *widget, GdkEvent *event, gpointer _unused)
@@ -31,63 +30,41 @@ gui_add(const char *name, GtkWidget *w)
 
 	frame = gtk_frame_new(name);
 
-	gtk_container_add(GTK_CONTAINER(frame), w);
-	gtk_widget_show(w);
+	gtk_frame_set_label_align(GTK_FRAME(frame), 0.5);
+	gtk_frame_set_child(GTK_FRAME(frame), w);
 
-	gtk_widget_show(frame);
-	gtk_box_pack_start(GTK_BOX(hbox), frame, FALSE, FALSE, 0);
+	gtk_box_append(GTK_BOX(hbox), frame);
 }
 
 void
 gui_step(void)
 {
-	GPollFD fds_gpoll[FD_SETSIZE];
-	gint max_priority;
-	int fds_length;
-	gint timeout;
-
-	g_main_context_acquire(main_context);
-
-	g_main_context_prepare(main_context, &max_priority);
-
-	fds_length = g_main_context_query(main_context,
-			max_priority, &timeout, fds_gpoll, FD_SETSIZE);
-
-	if (g_main_context_check(main_context, max_priority,
-			fds_gpoll, fds_length)) {
-		g_main_context_dispatch(main_context);
-	}
-
-	g_main_context_release(main_context);
-}
-
-void
-gui_flush(void)
-{
+	g_main_context_iteration(g_main_loop_get_context(loop), FALSE);
 }
 
 void
 gui_init(int *argcp, char ***argvp)
 {
-	gtk_init(argcp, argvp);
+	(void) argcp;
+	(void) argvp;
 
-	window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-	g_signal_connect(window, "delete-event", G_CALLBACK(gui_delete), NULL);
+	gtk_init();
 
-	gtk_window_set_title(GTK_WINDOW(window), "VM");
+	window = gtk_window_new();
+	g_signal_connect(window, "destroy", G_CALLBACK(gui_delete), NULL);
 
-	gtk_container_set_border_width(GTK_CONTAINER(window), 10);
+	gtk_window_set_title(GTK_WINDOW(window), "VM");
 
-	hbox = gtk_hbox_new(FALSE, 0);
-	gtk_widget_show(hbox);
-	gtk_container_add(GTK_CONTAINER(window), hbox);
+	hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
+	gtk_window_set_child(GTK_WINDOW(window), hbox);
 
-	gtk_widget_show(window);
+	gtk_widget_set_visible(window, true);
 
-	main_context = g_main_context_default();
+	loop = g_main_loop_new(NULL, FALSE);
 }
 
 void
 gui_exit(void)
 {
+	g_main_loop_unref(loop);
 }
diff --git a/src/gui.h b/src/gui.h
index 1ee5f79..e6dc292 100644
--- a/src/gui.h
+++ b/src/gui.h
@@ -6,10 +6,8 @@ gui_add(const char *name, GtkWidget *w);
 extern void
 gui_step(void);
 
-extern void
-gui_flush(void);
-
 extern void
 gui_init(int *argcp, char ***argvp);
+
 extern void
 gui_exit(void);
diff --git a/src/led.c b/src/led.c
index f56a6ba..24842af 100644
--- a/src/led.c
+++ b/src/led.c
@@ -1,5 +1,4 @@
 #include <assert.h>
-#include <stdio.h>
 #include <stdlib.h>
 
 #include <gtk/gtk.h>
@@ -8,72 +7,43 @@
 #include "led.h"
 
 struct cpssp {
-	GdkPixbuf *icon[2];
 	GtkWidget *widget;
 
 	int state_a;
 	int state_c;
+
+	GdkRGBA currentColor;
 };
 
 static void
-led_draw(GdkPixbuf *pixbuf, unsigned int r, unsigned int g, unsigned int b)
+led_draw(GtkDrawingArea *area, cairo_t *cr, int width, int height, gpointer user_data)
 {
-	int width, height, rowstride;
-	guchar *pixels, *p;
-	int x, y;
-
-	assert(gdk_pixbuf_get_n_channels(pixbuf) == 4);
-	assert(gdk_pixbuf_get_colorspace(pixbuf) == GDK_COLORSPACE_RGB);
-	assert(gdk_pixbuf_get_bits_per_sample(pixbuf) == 8);
-	assert(gdk_pixbuf_get_has_alpha(pixbuf));
-
-	width = gdk_pixbuf_get_width(pixbuf);
-	height = gdk_pixbuf_get_height(pixbuf);
-	rowstride = gdk_pixbuf_get_rowstride(pixbuf);
-	pixels = gdk_pixbuf_get_pixels(pixbuf);
-
-	for (y = 0; y < height; y++) {
-		for (x = 0; x < width; x++) {
-			int d2;
-
-			p = pixels + y * rowstride + x * 4;
-			d2 = (x-width/2)*(x-width/2) + (y-height/2)*(y-height/2);
-			if (d2 <= ((width-4)/2)*((width-4)/2)) {
-				/* Circle */
-				p[0] = r;
-				p[1] = g;
-				p[2] = b;
-				p[3] = 0xff;
-			} else if (d2 <= (width/2)*(width/2)) {
-				/* Frame */
-				p[0] = 0x00;
-				p[1] = 0x00;
-				p[2] = 0x00;
-				p[3] = 0xff;
-			} else {
-				/* Outside */
-				p[0] = 0;
-				p[1] = 0;
-				p[2] = 0;
-				p[3] = 0x00;
-			}
-		}
-	}
+	struct cpssp *data = (struct cpssp *) user_data;
+
+	(void) area;
+
+	gdk_cairo_set_source_rgba(cr, &data->currentColor);
+
+	const int RADIUS = 8;
+	cairo_arc(cr, width / 2.0, height / 2.0, RADIUS, 0, 2 * G_PI);
+	cairo_fill(cr);
+
+	cairo_set_source_rgb(cr, 0, 0, 0);
+	cairo_set_line_width(cr, 1);
+	cairo_arc(cr, width / 2.0, height / 2.0, RADIUS, 0, 2 * G_PI);
+	cairo_stroke(cr);
 }
 
 static void
 led_update(struct cpssp *cpssp)
 {
-	GdkPixbuf *icon;
-
 	if (cpssp->state_c < cpssp->state_a) {
-		icon = cpssp->icon[1];
+		cpssp->currentColor.alpha = 1.0;
 	} else {
-		icon = cpssp->icon[0];
+		cpssp->currentColor.alpha = 0.1;
 	}
 
-	gtk_image_set_from_pixbuf(GTK_IMAGE(cpssp->widget), icon);
-	
+	gtk_widget_queue_draw(cpssp->widget);
 }
 
 static void
@@ -119,16 +89,18 @@ led_create(
 	cpssp = malloc(sizeof(*cpssp));
 	assert(cpssp);
 
-	cpssp->icon[0] = gdk_pixbuf_new(GDK_COLORSPACE_RGB, 1, 8, 16, 16);
-	assert(cpssp->icon[0]);
-	led_draw(cpssp->icon[0], 0, 0, 0);
-	cpssp->icon[1] = gdk_pixbuf_new(GDK_COLORSPACE_RGB, 1, 8, 16, 16);
-	assert(cpssp->icon[1]);
-	led_draw(cpssp->icon[1], r, g, b);
+	cpssp->currentColor.red = (double) r / 0xFF;
+	cpssp->currentColor.green = (double) g / 0xFF;
+	cpssp->currentColor.blue = (double) b / 0xFF;
+	cpssp->currentColor.alpha = 1.0;
+
+	cpssp->widget = gtk_drawing_area_new();
+
+	gtk_drawing_area_set_content_width(GTK_DRAWING_AREA(cpssp->widget), 50);
+	gtk_drawing_area_set_content_height(GTK_DRAWING_AREA(cpssp->widget), 50);
 
-	cpssp->widget = gtk_image_new();
-	gtk_image_set_from_pixbuf(GTK_IMAGE(cpssp->widget), cpssp->icon[1]);
-	gtk_widget_show(cpssp->widget);
+	gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(cpssp->widget), led_draw,
+			cpssp, NULL);
 
 	gui_add(name, cpssp->widget);
 
diff --git a/src/poti.c b/src/poti.c
index b113c89..8ac34fe 100644
--- a/src/poti.c
+++ b/src/poti.c
@@ -1,5 +1,4 @@
 #include <assert.h>
-#include <stdio.h>
 #include <stdlib.h>
 #include <gtk/gtk.h>
 
@@ -30,7 +29,7 @@ poti_adj(GtkAdjustment *adj, gpointer _cpssp)
 {
 	struct cpssp *cpssp = _cpssp;
 
-	cpssp->state_adj = (int) adj->value;
+	cpssp->state_adj = (int) gtk_adjustment_get_value(adj);
 
 	poti_update(cpssp);
 }
@@ -69,23 +68,20 @@ poti_create(
 	static const struct sig_std_logic_funcs right_funcs = {
 		.std_logic_set = poti_right_set,
 	};
-	struct cpssp *cpssp;
-	GtkAdjustment *adj;
-	GtkWidget *scale;
 
-	cpssp = malloc(sizeof(*cpssp));
+	struct cpssp *cpssp = malloc(sizeof(*cpssp));
 	assert(cpssp);
 
-	adj = (GtkAdjustment *) gtk_adjustment_new(0.0, /* value */
-			0.0, /* lower */
+	GtkAdjustment *adj = gtk_adjustment_new(0.0,   /* value */
+			0.0,   /* lower */
 			110.0, /* upper + page size */
-			5.0, /* step increment */
-			10.0, /* page increment */
+			5.0,   /* step increment */
+			10.0,  /* page increment */
 			10.0 /* page size */);
 	g_signal_connect(adj, "value_changed",
 			G_CALLBACK(poti_adj), cpssp);
-	scale = gtk_hscale_new(adj);
-	gtk_widget_show(scale);
+	GtkWidget *scale = gtk_scale_new(GTK_ORIENTATION_HORIZONTAL, adj);
+	gtk_scale_set_draw_value(GTK_SCALE(scale), true);
 
 	gui_add(name, scale);
 
diff --git a/src/seg7.c b/src/seg7.c
index 52ff61b..5d0d738 100644
--- a/src/seg7.c
+++ b/src/seg7.c
@@ -1,8 +1,8 @@
 #include <assert.h>
-#include <stdio.h>
 #include <stdlib.h>
 #include <gtk/gtk.h>
 
+#include "cairo.h"
 #include "gui.h"
 #include "seg7.h"
 
@@ -19,82 +19,107 @@ struct cpssp {
 	int sum_seg[8];
 	int state_seg[8];
 	int state_anode;
+
+	int current_state[8];
 };
 
 static void
 seg7_hor(
-        GtkWidget *widget,
-        int state,
-        gint x,
-        gint y
+	cairo_t *cr,
+	int state,
+	gint x,
+	gint y
 )
-{       
-        GdkGC *gc = state 
-                        ? widget->style->fg_gc[widget->state]
-                        : widget->style->bg_gc[widget->state];
-        
-        gdk_draw_line(widget->window, gc, 
-                        x + 4, y - 2, x + LX - 4, y - 2);
-        gdk_draw_line(widget->window, gc, 
-                        x + 3, y - 1, x + LX - 3, y - 1);
-        gdk_draw_line(widget->window, gc,
-                        x + 2, y, x + LX - 2, y);
-        gdk_draw_line(widget->window, gc, 
-                        x + 3, y + 1, x + LX - 3, y + 1);
-        gdk_draw_line(widget->window, gc, 
-                        x + 4, y + 2, x + LX - 4, y + 2);
+{
+	if (! state)
+		return;
+
+	cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
+	cairo_set_line_width(cr, 1.0);
+
+	cairo_move_to(cr, x + 4, y - 2);
+	cairo_line_to(cr, x + LX - 4, y - 2);
+
+	cairo_move_to(cr, x + 3, y - 1);
+	cairo_line_to(cr, x + LX - 3, y - 1);
+
+	cairo_move_to(cr, x + 2, y);
+	cairo_line_to(cr, x + LX - 2, y);
+
+	cairo_move_to(cr, x + 3, y + 1);
+	cairo_line_to(cr, x + LX - 3, y + 1);
+
+	cairo_move_to(cr, x + 4, y + 2);
+	cairo_line_to(cr, x + LX - 4, y + 2);
+
+	cairo_stroke(cr);
 }
 
 static void
 seg7_vert(
-        GtkWidget *widget,
-        int state,
-        gint x,
-        gint y
+	cairo_t *cr,
+	int state,
+	gint x,
+	gint y
 )
-{       
-        GdkGC *gc = state 
-                        ? widget->style->fg_gc[widget->state]
-                        : widget->style->bg_gc[widget->state];
-        
-        gdk_draw_line(widget->window, gc, 
-                        x - 2, y + 4, x - 2, y + LY - 4);
-        gdk_draw_line(widget->window, gc, 
-                        x - 1, y + 3, x - 1, y + LY - 3);
-        gdk_draw_line(widget->window, gc,
-                        x, y + 2, x, y + LY - 2);
-        gdk_draw_line(widget->window, gc, 
-                        x + 1, y + 3, x + 1, y + LY - 3);
-        gdk_draw_line(widget->window, gc, 
-                        x + 2, y + 4, x + 2, y + LY - 4);
+{
+	if (! state) return;
+
+	cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
+	cairo_set_line_width(cr, 1.0);
+
+	cairo_move_to(cr, x - 2, y + 4);
+	cairo_line_to(cr, x - 2, y + LY - 4);
+
+	cairo_move_to(cr, x - 1, y + 3);
+	cairo_line_to(cr, x - 1, y + LY - 3);
+
+	cairo_move_to(cr, x, y + 2);
+	cairo_line_to(cr, x, y + LY - 2);
+
+	cairo_move_to(cr, x + 1, y + 3);
+	cairo_line_to(cr, x + 1, y + LY - 3);
+
+	cairo_move_to(cr, x + 2, y + 4);
+	cairo_line_to(cr, x + 2, y + LY - 4);
+
+	cairo_stroke(cr);
 }
 
 static void
 seg7_dot(
-        GtkWidget *widget,
-        int state,
-        gint x,
-        gint y
+	cairo_t *cr,
+	int state,
+	gint x,
+	gint y
 )
-{       
-        GdkGC *gc = state 
-                        ? widget->style->fg_gc[widget->state]
-                        : widget->style->bg_gc[widget->state];
-        
-        gdk_draw_line(widget->window, gc, 
-                        x - 2, y - 2, x + 2, y - 2);
-        gdk_draw_line(widget->window, gc, 
-                        x - 2, y - 1, x + 2, y - 1);
-        gdk_draw_line(widget->window, gc, 
-                        x - 2, y + 0, x + 2, y + 0);
-        gdk_draw_line(widget->window, gc, 
-                        x - 2, y + 1, x + 2, y + 1);
-        gdk_draw_line(widget->window, gc, 
-                        x - 2, y + 2, x + 2, y + 2);
+{
+	if (! state)
+		return;
+
+	cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
+	cairo_set_line_width(cr, 1.0);
+
+	cairo_move_to(cr, x - 2, y - 2);
+	cairo_line_to(cr, x + 2, y - 2);
+
+	cairo_move_to(cr, x - 2, y - 1);
+	cairo_line_to(cr, x + 2, y - 1);
+
+	cairo_move_to(cr, x - 2, y);
+	cairo_line_to(cr, x + 2, y);
+
+	cairo_move_to(cr, x - 2, y + 1);
+	cairo_line_to(cr, x + 2, y + 1);
+
+	cairo_move_to(cr, x - 2, y + 2);
+	cairo_line_to(cr, x + 2, y + 2);
+
+	cairo_stroke(cr);
 }
 
 static const struct {
-	void (*func)(GtkWidget *widget, int state, gint x, gint y);
+	void (*func)(cairo_t *cr, int state, gint x, gint y);
 	gint x;
 	gint y;
 } seg7_table[8] = {
@@ -105,35 +130,22 @@ static const struct {
 	/* E */  { seg7_vert, 0 * LX, 1 * LY },
 	/* F */  { seg7_vert, 0 * LX, 0 * LY },
 	/* G */  { seg7_hor, 0 * LX, 1 * LY },
-	/* DP */ { seg7_dot, 1 * LX + LSPACE / 2, LY * 2 },
+	/* DP */ { seg7_dot, 1 * LX + LSPACE / 2, LY * 2},
 };
 
-static int
-seg7_expose(GtkWidget *w, GdkEventExpose *event, gpointer _cpssp)
+static void
+seg7_draw(GtkDrawingArea *area, cairo_t *cr, int width, int height, gpointer _cpssp)
 {
-	struct cpssp *cpssp = _cpssp;
-	int i;
+	(void) area;
+	(void) width;
+	(void) height;
 
-	(void) w;
-	(void) event;
-
-	if (0 < event->count) {
-		return FALSE;
-	}
-
-	gdk_window_clear_area(cpssp->gui_area->window,
-			0, 0,
-			cpssp->gui_area->allocation.width,
-			cpssp->gui_area->allocation.height);
+	struct cpssp *cpssp = _cpssp;
 
-	for (i = 0; i < 8; i++) {
-		(*seg7_table[i].func)(cpssp->gui_area,
-				cpssp->sum_seg[i],
-				OFFX + seg7_table[i].x,
-				OFFY + seg7_table[i].y);
+	for (int i = 0; i < 8; i++) {
+		(*seg7_table[i].func)(cr, cpssp->current_state[i], OFFX + seg7_table[i].x,
+			OFFY + seg7_table[i].y);
 	}
-
-	return FALSE;
 }
 
 static void
@@ -217,17 +229,16 @@ seg7_step(void *_cpssp)
 	count = 0;
 
 	for (i = 0; i < 8; i++) {
-		(*seg7_table[i].func)(cpssp->gui_area,
-				10000 / 4 < cpssp->sum_seg[i],
-				OFFX + seg7_table[i].x,
-				OFFY + seg7_table[i].y);
+		cpssp->current_state[i] = 10000 / 4 < cpssp->sum_seg[i];
+
 		cpssp->sum_seg[i] = 0;
 	}
+	gtk_widget_queue_draw(cpssp->gui_area);
 }
 
 void *
 seg7_create(
-	const char *name, 
+	const char *name,
 	struct sig_std_logic *port_e,
 	struct sig_std_logic *port_d,
 	struct sig_std_logic *port_anode0,
@@ -275,11 +286,14 @@ seg7_create(
 	assert(cpssp);
 
 	cpssp->gui_area = gtk_drawing_area_new();
-	gtk_widget_set_size_request(cpssp->gui_area,
-			OFFX + LX + OFFX, OFFY + 2 * LY + OFFY);
-	g_signal_connect(G_OBJECT(cpssp->gui_area), "expose_event",
-			G_CALLBACK(seg7_expose), cpssp);
-	gtk_widget_show(cpssp->gui_area);
+
+	gtk_drawing_area_set_content_width(GTK_DRAWING_AREA(cpssp->gui_area),
+			OFFX + LX + OFFX);
+	gtk_drawing_area_set_content_height(GTK_DRAWING_AREA(cpssp->gui_area),
+			OFFY + 2 * LY + OFFY);
+
+	gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(cpssp->gui_area), seg7_draw,
+			cpssp, NULL);
 
 	gui_add(name, cpssp->gui_area);
 
