rofi 2.0.0
view.c
Go to the documentation of this file.
1/*
2 * rofi
3 *
4 * MIT/X11 License
5 * Copyright © 2013-2020 Qball Cow <qball@gmpclient.org>
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining
8 * a copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sublicense, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be
16 * included in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 */
27
29#define G_LOG_DOMAIN "View"
30
31#include <config.h>
32#include <errno.h>
33#include <locale.h>
34#include <signal.h>
35#include <stdint.h>
36#include <stdio.h>
37#include <stdlib.h>
38#include <string.h>
39#include <time.h>
40#include <unistd.h>
41
42#include <cairo.h>
43
44#include "rofi.h"
45#include "settings.h"
46#include "timings.h"
47
48#include "display.h"
49#include "helper-theme.h"
50#include "helper.h"
51#include "mode.h"
52#include "modes/modes.h"
53
54#include "view-internal.h"
55#include "view.h"
56
57#include "theme.h"
58
65static void wayland_rofi_view_update(RofiViewState *state, gboolean qr);
66
70static struct {
76 unsigned long long count;
80 gboolean fullscreen;
81
84} WlState = {
85 .flags = MENU_NORMAL,
86 .idle_timeout = 0,
87 .count = 0L,
88 .repaint_source = 0,
89 .fullscreen = FALSE,
90 .monitor_width = 0,
91 .monitor_height = 0,
92};
93
94static void wayland_rofi_view_get_current_monitor(int *width, int *height) {
95 // TODO: handle changing monitor resolution
96 if (WlState.monitor_width == 0 && WlState.monitor_height == 0) {
98 &WlState.monitor_height);
99 }
100
101 if (width) {
102 *width = WlState.monitor_width;
103 }
104 if (height) {
105 *height = WlState.monitor_height;
106 }
107}
108
109static gboolean wayland_rofi_view_repaint(G_GNUC_UNUSED void *data) {
111 if (state) {
112 // Repaint the view (if needed).
113 // After a resize the edit_pixmap surface might not contain anything
114 // anymore. If we already re-painted, this does nothing.
116 WlState.repaint_source = 0;
117 }
118 return G_SOURCE_REMOVE;
119}
120
125
127 G_GNUC_UNUSED RofiViewState *state) {}
128
130 return rofi_theme_get_position(WIDGET(state->main_window), "location",
131 loc_transtable[config.location]);
132}
133
135 char *property = ori == ROFI_ORIENTATION_HORIZONTAL ? "x-offset" : "y-offset";
136
137 RofiDistance offset =
138 rofi_theme_get_distance(WIDGET(state->main_window), property, 0);
139 return distance_get_pixel(offset, ori);
140}
141
143 if (state == NULL) {
144 return;
145 }
146 int offset_x = rofi_get_offset_px(state, ROFI_ORIENTATION_HORIZONTAL);
147 int offset_y = rofi_get_offset_px(state, ROFI_ORIENTATION_VERTICAL);
148
149 widget_resize(WIDGET(state->main_window), state->width, state->height);
150 display_set_surface_dimensions(state->width, state->height, offset_x,
151 offset_y, rofi_get_location(state));
153}
154
155static void wayland_rofi_view_set_size(RofiViewState *state, gint width,
156 gint height) {
157 if (width > -1) {
158 state->width = width;
159 }
160 if (height > -1) {
161 state->height = height;
162 }
164}
165
166static void wayland_rofi_view_get_size(RofiViewState *state, gint *width,
167 gint *height) {
168 *width = state->width;
169 *height = state->height;
170}
171
172static void wayland_rofi_view_ping_mouse(RofiViewState *state) { (void)state; }
173
174static gboolean wayland_rofi_view_reload_idle(G_GNUC_UNUSED gpointer data) {
176
177 if (state) {
178 // For UI update on this.
179 if (state->tb_total_rows) {
180 char *r = g_strdup_printf("%u", mode_get_num_entries(state->sw));
181 textbox_text(state->tb_total_rows, r);
182 g_free(r);
183 }
184 state->reload = TRUE;
185 state->refilter = TRUE;
186
188 }
189 WlState.idle_timeout = 0;
190 return G_SOURCE_REMOVE;
191}
192
193static void wayland_rofi_view_reload(void) {
194 // @TODO add check if current view is equal to the callee
195 if (WlState.idle_timeout == 0) {
196 WlState.idle_timeout =
197 g_timeout_add(1000 / 15, wayland_rofi_view_reload_idle, NULL);
198 }
199}
202 if (state && WlState.repaint_source == 0) {
203 WlState.count++;
204 g_debug("redraw %llu", WlState.count);
205
207
208 WlState.repaint_source = g_idle_add_full(
209 G_PRIORITY_HIGH_IDLE, wayland_rofi_view_repaint, NULL, NULL);
210 }
211}
212
213static void wayland___create_window(MenuFlags menu_flags) {
215
216 TICK_N("create cairo surface");
217 // TODO should we update the drawable each time?
218 PangoContext *p = pango_context_new();
219 pango_context_set_font_map(p, pango_cairo_font_map_get_default());
220 TICK_N("pango cairo font setup");
221
222 WlState.flags = menu_flags;
223 // Setup dpi
224 PangoFontMap *font_map = pango_cairo_font_map_get_default();
225 if (config.dpi > 1) {
226 pango_cairo_font_map_set_resolution((PangoCairoFontMap *)font_map,
227 (double)config.dpi);
228 } else if (config.dpi == 0 || config.dpi == 1) {
229 // This is an heuristic that works well for simple cases (eg single monitor)
230 // Accurate dpi information only comes after we display the first surface on
231 // the screen when it's too late to use for metric units.
232 double dpi = wayland_get_dpi_estimation();
233 if (dpi >= 0) {
234 config.dpi = dpi;
235 pango_cairo_font_map_set_resolution((PangoCairoFontMap *)font_map, dpi);
236 } else {
237 g_warning(
238 "DPI auto-detect failed, the output is not known yet or does not "
239 "provide a physical size");
240 config.dpi =
241 pango_cairo_font_map_get_resolution((PangoCairoFontMap *)font_map);
242 }
243 } else {
244 // default pango is 96.
245 config.dpi =
246 pango_cairo_font_map_get_resolution((PangoCairoFontMap *)font_map);
247 }
248 // Setup font.
249 // Dummy widget.
250 box *win = box_create(NULL, "window", ROFI_ORIENTATION_HORIZONTAL);
251 const char *font =
252 rofi_theme_get_string(WIDGET(win), "font", config.menu_font);
253 if (font) {
254 PangoFontDescription *pfd = pango_font_description_from_string(font);
255 if (helper_validate_font(pfd, font)) {
256 pango_context_set_font_description(p, pfd);
257 }
258 pango_font_description_free(pfd);
259 }
260 PangoLanguage *l = pango_language_get_default();
261 pango_context_set_language(p, l);
262 TICK_N("configure font");
263
264 // Tell textbox to use this context.
266 // cleanup
267 g_object_unref(p);
268
269 WlState.fullscreen = rofi_theme_get_boolean(WIDGET(win), "fullscreen", FALSE);
270
271 if (WlState.fullscreen) {
273 }
274
275 widget_free(WIDGET(win));
276
277 TICK_N("done");
278}
279
286 int screen_width = 1920;
287 display_get_surface_dimensions(&screen_width, NULL);
288
289 if (WlState.fullscreen == TRUE) {
290 state->width = screen_width;
291 return;
292 }
293
294 // Calculate as float to stop silly, big rounding down errors.
295 state->width = (screen_width / 100.0f) * DEFAULT_MENU_WIDTH;
296 // Use theme configured width, if set.
298 "width", state->width);
300}
301
302static void wayland_rofi_view_update(RofiViewState *state, gboolean qr) {
303 if (!widget_need_redraw(WIDGET(state->main_window))) {
304 return;
305 }
306 g_debug("Redraw view");
307 TICK();
308 if (state->pool == NULL) {
309 state->pool = display_buffer_pool_new(state->width, state->height);
310 }
311 cairo_surface_t *surface = display_buffer_pool_get_next_buffer(state->pool);
312 if (surface == NULL) {
313 // no available buffer, bail out
314 return;
315 }
316 cairo_t *d = cairo_create(surface);
317 cairo_set_operator(d, CAIRO_OPERATOR_SOURCE);
318 // Paint the background transparent.
319 cairo_set_source_rgba(d, 0, 0, 0, 0.0);
320 guint scale = display_scale();
321 cairo_surface_set_device_scale(surface, scale, scale);
322 cairo_paint(d);
323 TICK_N("Background");
324
325 // Always paint as overlay over the background.
326 cairo_set_operator(d, CAIRO_OPERATOR_OVER);
327 widget_draw(WIDGET(state->main_window), d);
328
329 TICK_N("widgets");
330 cairo_destroy(d);
331 display_surface_commit(surface);
332
333 if (qr) {
335 }
336}
337
343void process_result(RofiViewState *state);
344
346 if (WlState.repaint_source == 0) {
347 WlState.repaint_source = g_idle_add_full(
348 G_PRIORITY_HIGH_IDLE, wayland_rofi_view_repaint, NULL, NULL);
349 }
350}
351
353 if (WlState.fullscreen == TRUE) {
354 int height = 1080;
355 display_get_surface_dimensions(NULL, &height);
356 return height;
357 }
358
359 RofiDistance h =
360 rofi_theme_get_distance(WIDGET(state->main_window), "height", 0);
361 unsigned int height = distance_get_pixel(h, ROFI_ORIENTATION_VERTICAL);
362 // If height is set, return it.
363 if (height > 0) {
364 return height;
365 }
366 // Autosize based on widgets.
367 widget *main_window = WIDGET(state->main_window);
368
369 return widget_get_desired_height(main_window, state->width);
370}
371
373
374static void wayland_rofi_view_cleanup(void) {
375 g_debug("Cleanup.");
376 if (WlState.idle_timeout > 0) {
377 g_source_remove(WlState.idle_timeout);
378 WlState.idle_timeout = 0;
379 }
380 if (CacheState.refilter_timeout > 0) {
381 g_source_remove(CacheState.refilter_timeout);
382 CacheState.refilter_timeout = 0;
383 }
384 if (CacheState.overlay_timeout) {
385 g_source_remove(CacheState.overlay_timeout);
386 CacheState.overlay_timeout = 0;
387 }
388 if (CacheState.user_timeout > 0) {
389 g_source_remove(CacheState.user_timeout);
390 CacheState.user_timeout = 0;
391 }
392 if (WlState.repaint_source > 0) {
393 g_source_remove(WlState.repaint_source);
394 WlState.repaint_source = 0;
395 }
396
398}
399
400static void
401wayland_rofi_view_set_window_title(G_GNUC_UNUSED const char *title) {}
402
405 if (state == NULL) {
406 return;
407 }
408 display_buffer_pool_free(state->pool);
409 state->pool = NULL;
410 wayland_rofi_view_update(state, TRUE);
411}
412
414 .update = wayland_rofi_view_update,
415 .temp_configure_notify = NULL,
416 .temp_click_to_exit = NULL,
417 .frame_callback = wayland_rofi_view_frame_callback,
418 .queue_redraw = wayland_rofi_view_queue_redraw,
419
420 .set_window_title = wayland_rofi_view_set_window_title,
421 .calculate_window_position = wayland_rofi_view_calculate_window_position,
422 .calculate_window_height = wayland_rofi_view_calculate_window_height,
423 .calculate_window_width = wayland_rofi_view_calculate_window_width,
424 .window_update_size = wayland_rofi_view_window_update_size,
426 .ping_mouse = wayland_rofi_view_ping_mouse,
427
428 .cleanup = wayland_rofi_view_cleanup,
430 .reload = wayland_rofi_view_reload,
431
432 .__create_window = wayland___create_window,
433 .get_window = NULL,
434 .get_current_monitor = wayland_rofi_view_get_current_monitor,
435
436 .set_size = wayland_rofi_view_set_size,
437 .get_size = wayland_rofi_view_get_size,
438
439 .pool_refresh = wayland_rofi_view_pool_refresh,
440};
441
void display_early_cleanup(void)
Definition display.c:30
guint display_scale(void)
Definition display.c:42
void display_set_fullscreen_mode(void)
Definition display.c:48
@ WL_CENTER
Definition rofi-types.h:235
@ WL_SOUTH
Definition rofi-types.h:241
@ WL_WEST
Definition rofi-types.h:243
@ WL_NORTH
Definition rofi-types.h:237
@ WL_EAST
Definition rofi-types.h:239
gboolean helper_validate_font(PangoFontDescription *pfd, const char *font)
Definition helper.c:652
unsigned int mode_get_num_entries(const Mode *mode)
Definition mode.c:70
#define TICK()
Definition timings.h:64
#define TICK_N(a)
Definition timings.h:69
void textbox_set_pango_context(const char *font, PangoContext *p)
Definition textbox.c:973
void textbox_text(textbox *tb, const char *text)
Definition textbox.c:403
RofiViewState * rofi_view_get_active(void)
Definition view.c:299
MenuFlags
Definition view.h:54
void rofi_view_maybe_update(RofiViewState *state)
Definition view.c:1495
@ MENU_NORMAL
Definition view.h:56
void input_history_save(void)
Definition view.c:526
void input_history_initialize(void)
Definition view.c:483
void rofi_view_pool_refresh(void)
Definition view.c:2179
box * box_create(widget *parent, const char *name, RofiOrientation type)
Definition box.c:347
struct _box box
Definition box.h:49
void widget_queue_redraw(widget *wid)
Definition widget.c:487
void widget_free(widget *wid)
Definition widget.c:425
void widget_draw(widget *wid, cairo_t *d)
Definition widget.c:140
struct _widget widget
Definition widget.h:49
void widget_resize(widget *wid, short w, short h)
Definition widget.c:92
#define WIDGET(a)
Definition widget.h:117
int widget_get_desired_height(widget *wid, const int width)
Definition widget.c:644
gboolean widget_need_redraw(widget *wid)
Definition widget.c:500
RofiOrientation
Definition rofi-types.h:139
@ ROFI_ORIENTATION_HORIZONTAL
Definition rofi-types.h:141
@ ROFI_ORIENTATION_VERTICAL
Definition rofi-types.h:140
Settings config
#define DEFAULT_MENU_WIDTH
Definition settings.h:229
textbox * tb_total_rows
int rofi_theme_get_position(const widget *wid, const char *property, int def)
Definition theme.c:818
int distance_get_pixel(RofiDistance d, RofiOrientation ori)
Definition theme.c:1406
int rofi_theme_get_boolean(const widget *wid, const char *property, int def)
Definition theme.c:903
RofiDistance rofi_theme_get_distance(const widget *wid, const char *property, int def)
Definition theme.c:877
const char * rofi_theme_get_string(const widget *wid, const char *property, const char *def)
Definition theme.c:989
struct _view_proxy view_proxy
void process_result(RofiViewState *state)
Definition rofi.c:238
struct _rofi_view_cache_state CacheState
Definition view.c:75
double wayland_get_dpi_estimation(void)
Definition display.c:1207
void display_surface_commit(cairo_surface_t *surface)
Definition display.c:306
cairo_surface_t * display_buffer_pool_get_next_buffer(wayland_buffer_pool *pool)
Definition display.c:283
gboolean display_get_surface_dimensions(int *width, int *height)
Definition display.c:1652
void wayland_display_set_cursor_type(RofiCursorType type)
Definition display.c:746
void display_buffer_pool_free(wayland_buffer_pool *self)
Definition display.c:227
void display_set_surface_dimensions(int width, int height, int x_margin, int y_margin, int loc)
Definition display.c:1665
wayland_buffer_pool * display_buffer_pool_new(gint width, gint height)
Definition display.c:157
static int rofi_get_offset_px(RofiViewState *state, RofiOrientation ori)
Definition view.c:134
static void wayland_rofi_view_get_size(RofiViewState *state, gint *width, gint *height)
Definition view.c:166
const view_proxy * wayland_view_proxy
Definition view.c:442
static int rofi_get_location(RofiViewState *state)
Definition view.c:129
guint idle_timeout
Definition view.c:74
static struct @367071131060133350271250111004244213234203174335 WlState
static gboolean wayland_rofi_view_reload_idle(G_GNUC_UNUSED gpointer data)
Definition view.c:174
static void wayland_rofi_view_hide(void)
Definition view.c:372
static void wayland_rofi_view_set_window_title(G_GNUC_UNUSED const char *title)
Definition view.c:401
static void wayland_rofi_view_calculate_window_width(RofiViewState *state)
Definition view.c:285
static void wayland_rofi_view_calculate_window_position(G_GNUC_UNUSED RofiViewState *state)
Definition view.c:126
static void wayland_rofi_view_reload(void)
Definition view.c:193
static int wayland_rofi_view_calculate_window_height(RofiViewState *state)
Definition view.c:352
static void wayland_rofi_view_set_size(RofiViewState *state, gint width, gint height)
Definition view.c:155
static const int loc_transtable[9]
Definition view.c:121
static void wayland_rofi_view_cleanup(void)
Definition view.c:374
static void wayland_rofi_view_frame_callback(void)
Definition view.c:345
static void wayland_rofi_view_get_current_monitor(int *width, int *height)
Definition view.c:94
static void wayland_rofi_view_ping_mouse(RofiViewState *state)
Definition view.c:172
int monitor_width
Definition view.c:82
int monitor_height
Definition view.c:83
static void wayland_rofi_view_window_update_size(RofiViewState *state)
Definition view.c:142
static void wayland___create_window(MenuFlags menu_flags)
Definition view.c:213
MenuFlags flags
Definition view.c:72
unsigned long long count
Definition view.c:76
static view_proxy view_
Definition view.c:413
static void wayland_rofi_view_queue_redraw(void)
Definition view.c:200
static gboolean wayland_rofi_view_repaint(G_GNUC_UNUSED void *data)
Definition view.c:109
static void wayland_rofi_view_update(RofiViewState *state, gboolean qr)
Definition view.c:302
static void wayland_rofi_view_pool_refresh(void)
Definition view.c:403
gboolean fullscreen
Definition view.c:80
guint repaint_source
Definition view.c:78