1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
|
// SPDX-License-Identifier: GPL-2.0
#include "gtk.h"
#include "../evsel.h"
#include "../sort.h"
#include "../hist.h"
#include "../helpline.h"
#include <glib-unix.h>
#include <signal.h>
/*
* SIGINT/SIGQUIT/SIGTERM are asynchronous: deferring the actual exit to a
* GLib source dispatched from the main loop means it always runs on the
* main thread, serialized with everything else the main loop does
* (including perf_gtk__error()'s updates to perf_gtk__error_loops), instead
* of racing them from arbitrary signal-handler context.
*/
static gboolean perf_gtk__quit_signal(gpointer data __maybe_unused)
{
perf_gtk__exit(false);
return G_SOURCE_REMOVE;
}
void perf_gtk__install_quit_signals(void)
{
g_unix_signal_add(SIGINT, perf_gtk__quit_signal, NULL);
g_unix_signal_add(SIGQUIT, perf_gtk__quit_signal, NULL);
g_unix_signal_add(SIGTERM, perf_gtk__quit_signal, NULL);
}
/*
* SIGSEGV/SIGFPE are synchronous faults: there's no "later" to defer to,
* and no safe way to run GTK/GLib code (or anything else non-async-signal-
* safe) from the faulting context. Report and let the default disposition
* (core dump) happen instead of trying to tear down GTK state here.
*/
void perf_gtk__fatal_signal(int sig)
{
psignal(sig, "perf");
signal(sig, SIG_DFL);
raise(sig);
}
void perf_gtk__resize_window(GtkWidget *window)
{
GdkRectangle rect;
GdkMonitor *monitor;
GdkDisplay *display;
GListModel *monitors;
int height;
int width;
display = gtk_widget_get_display(window);
monitors = gdk_display_get_monitors(display);
monitor = g_list_model_get_item(monitors, 0);
if (!monitor) {
gtk_window_set_default_size(GTK_WINDOW(window), 800, 600);
return;
}
gdk_monitor_get_geometry(monitor, &rect);
g_object_unref(monitor);
width = rect.width * 3 / 4;
height = rect.height * 3 / 4;
gtk_window_set_default_size(GTK_WINDOW(window), width, height);
}
static GMainLoop *perf_gtk__main_loop;
void perf_gtk__quit_main_loop(void)
{
if (perf_gtk__main_loop)
g_main_loop_quit(perf_gtk__main_loop);
}
static gboolean perf_gtk__close_request(GtkWidget *widget __maybe_unused,
gpointer data __maybe_unused)
{
perf_gtk__quit_main_loop();
return FALSE;
}
void perf_gtk__run_main_loop(GtkWidget *window)
{
g_signal_connect(window, "close-request",
G_CALLBACK(perf_gtk__close_request), NULL);
perf_gtk__main_loop = g_main_loop_new(NULL, FALSE);
g_main_loop_run(perf_gtk__main_loop);
g_clear_pointer(&perf_gtk__main_loop, g_main_loop_unref);
}
const char *perf_gtk__get_percent_color(double percent)
{
if (percent >= MIN_RED)
return "<span fgcolor='red'>";
if (percent >= MIN_GREEN)
return "<span fgcolor='dark green'>";
return NULL;
}
static void perf_gtk__hide_widget(GtkWidget *widget, gint response_id __maybe_unused,
gpointer data __maybe_unused)
{
gtk_widget_set_visible(widget, FALSE);
}
GtkWidget *perf_gtk__setup_info_bar(void)
{
GtkWidget *info_bar;
GtkWidget *label;
info_bar = gtk_info_bar_new();
gtk_widget_set_visible(info_bar, FALSE);
label = gtk_label_new("");
gtk_widget_set_visible(label, TRUE);
gtk_info_bar_add_child(GTK_INFO_BAR(info_bar), label);
gtk_info_bar_add_button(GTK_INFO_BAR(info_bar), "_OK",
GTK_RESPONSE_OK);
g_signal_connect(info_bar, "response",
G_CALLBACK(perf_gtk__hide_widget), NULL);
pgctx->info_bar = info_bar;
pgctx->message_label = label;
return info_bar;
}
GtkWidget *perf_gtk__setup_statusbar(void)
{
GtkWidget *stbar;
unsigned ctxid;
stbar = gtk_statusbar_new();
ctxid = gtk_statusbar_get_context_id(GTK_STATUSBAR(stbar),
"perf report");
pgctx->statbar = stbar;
pgctx->statbar_ctx_id = ctxid;
return stbar;
}
|