rofi  1.7.5
view.c
Go to the documentation of this file.
1 /*
2  * rofi
3  *
4  * MIT/X11 License
5  * Copyright © 2013-2022 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 #include <xcb/xcb_ewmh.h>
42 #include <xcb/xcb_icccm.h>
43 #include <xcb/xkb.h>
44 #include <xkbcommon/xkbcommon-x11.h>
45 
46 #include <cairo-xcb.h>
47 #include <cairo.h>
48 
50 #define SN_API_NOT_YET_FROZEN
51 #include "rofi.h"
52 #include <libsn/sn.h>
53 
54 #include "settings.h"
55 #include "timings.h"
56 
57 #include "display.h"
58 #include "helper-theme.h"
59 #include "helper.h"
60 #include "mode.h"
61 #include "modes/modes.h"
62 #include "xcb-internal.h"
63 #include "xrmoptions.h"
64 
65 #include "view-internal.h"
66 #include "view.h"
67 
68 #include "theme.h"
69 
70 #include "xcb.h"
71 
78 void rofi_view_update(RofiViewState *state, gboolean qr);
79 
80 static int rofi_view_calculate_height(RofiViewState *state);
81 
83 GThreadPool *tpool = NULL;
84 
87 
91 struct {
93  xcb_window_t main_window;
95  cairo_surface_t *fake_bg;
97  xcb_gcontext_t gc;
99  xcb_pixmap_t edit_pixmap;
101  cairo_surface_t *edit_surf;
103  cairo_t *edit_draw;
109  GQueue views;
120  unsigned long long count;
124  gboolean fullscreen;
127 } CacheState = {
128  .main_window = XCB_WINDOW_NONE,
129  .fake_bg = NULL,
130  .edit_surf = NULL,
131  .edit_draw = NULL,
132  .fake_bgrel = FALSE,
133  .flags = MENU_NORMAL,
134  .views = G_QUEUE_INIT,
135  .idle_timeout = 0,
136  .refilter_timeout = 0,
137  .refilter_timeout_count = 0,
138  .user_timeout = 0,
139  .count = 0L,
140  .repaint_source = 0,
141  .fullscreen = FALSE,
142 };
143 
144 void rofi_view_get_current_monitor(int *width, int *height) {
145  if (width) {
146  *width = CacheState.mon.w;
147  }
148  if (height) {
149  *height = CacheState.mon.h;
150  }
151 }
152 static char *get_matching_state(void) {
153  if (config.case_sensitive) {
154  if (config.sort) {
155  return "±";
156  }
157  return "-";
158  }
159  if (config.sort) {
160  return "+";
161  }
162  return " ";
163 }
164 
168 static int lev_sort(const void *p1, const void *p2, void *arg) {
169  const int *a = p1;
170  const int *b = p2;
171  int *distances = arg;
172 
173  return distances[*a] - distances[*b];
174 }
175 
180  const char *outp = g_getenv("ROFI_PNG_OUTPUT");
181  if (CacheState.edit_surf == NULL) {
182  // Nothing to store.
183  g_warning("There is no rofi surface to store");
184  return;
185  }
186  const char *xdg_pict_dir = g_get_user_special_dir(G_USER_DIRECTORY_PICTURES);
187  if (outp == NULL && xdg_pict_dir == NULL) {
188  g_warning("XDG user picture directory or ROFI_PNG_OUTPUT is not set. "
189  "Cannot store screenshot.");
190  return;
191  }
192  // Get current time.
193  GDateTime *now = g_date_time_new_now_local();
194  // Format filename.
195  char *timestmp = g_date_time_format(now, "rofi-%Y-%m-%d-%H%M");
196  char *filename = g_strdup_printf("%s-%05d.png", timestmp, 0);
197  // Build full path
198  char *fpath = NULL;
199  if (outp == NULL) {
200  int index = 0;
201  fpath = g_build_filename(xdg_pict_dir, filename, NULL);
202  while (g_file_test(fpath, G_FILE_TEST_EXISTS) && index < 99999) {
203  g_free(fpath);
204  g_free(filename);
205  // Try the next index.
206  index++;
207  // Format filename.
208  filename = g_strdup_printf("%s-%05d.png", timestmp, index);
209  // Build full path
210  fpath = g_build_filename(xdg_pict_dir, filename, NULL);
211  }
212  } else {
213  fpath = g_strdup(outp);
214  }
215  fprintf(stderr, color_green "Storing screenshot %s\n" color_reset, fpath);
216  cairo_status_t status =
217  cairo_surface_write_to_png(CacheState.edit_surf, fpath);
218  if (status != CAIRO_STATUS_SUCCESS) {
219  g_warning("Failed to produce screenshot '%s', got error: '%s'", fpath,
220  cairo_status_to_string(status));
221  }
222  g_free(fpath);
223  g_free(filename);
224  g_free(timestmp);
225  g_date_time_unref(now);
226 }
227 
232 gboolean do_bench = TRUE;
233 
237 static struct {
239  GTimer *time;
241  uint64_t draws;
243  double last_ts;
245  double min;
246 } BenchMark = {.time = NULL, .draws = 0, .last_ts = 0.0, .min = G_MAXDOUBLE};
247 
248 static gboolean bench_update(void) {
249  if (!config.benchmark_ui) {
250  return FALSE;
251  }
252  BenchMark.draws++;
253  if (BenchMark.time == NULL) {
254  BenchMark.time = g_timer_new();
255  }
256 
257  if ((BenchMark.draws & 1023) == 0) {
258  double ts = g_timer_elapsed(BenchMark.time, NULL);
259  double fps = 1024 / (ts - BenchMark.last_ts);
260 
261  if (fps < BenchMark.min) {
262  BenchMark.min = fps;
263  }
264  printf("current: %.2f fps, avg: %.2f fps, min: %.2f fps, %lu draws\r\n",
265  fps, BenchMark.draws / ts, BenchMark.min, BenchMark.draws);
266 
267  BenchMark.last_ts = ts;
268  }
269  return TRUE;
270 }
271 
272 static gboolean rofi_view_repaint(G_GNUC_UNUSED void *data) {
273  if (current_active_menu) {
274  // Repaint the view (if needed).
275  // After a resize the edit_pixmap surface might not contain anything
276  // anymore. If we already re-painted, this does nothing.
277 
278  TICK_N("Update start");
280  g_debug("expose event");
281  TICK_N("Expose");
282  xcb_copy_area(xcb->connection, CacheState.edit_pixmap,
283  CacheState.main_window, CacheState.gc, 0, 0, 0, 0,
285  xcb_flush(xcb->connection);
286  TICK_N("flush");
287  CacheState.repaint_source = 0;
288  }
289  return (bench_update() == TRUE) ? G_SOURCE_CONTINUE : G_SOURCE_REMOVE;
290 }
291 
293  if (state->prompt) {
294  const char *str = mode_get_display_name(state->sw);
295  textbox_text(state->prompt, str);
296  }
297 }
298 
311 static const int loc_transtable[9] = {
314  WL_WEST};
316  int location = rofi_theme_get_position(WIDGET(state->main_window), "location",
318  int anchor =
319  rofi_theme_get_position(WIDGET(state->main_window), "anchor", location);
320 
321  if (CacheState.fullscreen) {
322  state->x = CacheState.mon.x;
323  state->y = CacheState.mon.y;
324  return;
325  }
326  state->y = CacheState.mon.y + (CacheState.mon.h) / 2;
327  state->x = CacheState.mon.x + (CacheState.mon.w) / 2;
328  // Determine window location
329  switch (location) {
330  case WL_NORTH_WEST:
331  state->x = CacheState.mon.x;
332  /* FALLTHRU */
333  case WL_NORTH:
334  state->y = CacheState.mon.y;
335  break;
336  case WL_NORTH_EAST:
337  state->y = CacheState.mon.y;
338  /* FALLTHRU */
339  case WL_EAST:
340  state->x = CacheState.mon.x + CacheState.mon.w;
341  break;
342  case WL_SOUTH_EAST:
343  state->x = CacheState.mon.x + CacheState.mon.w;
344  /* FALLTHRU */
345  case WL_SOUTH:
346  state->y = CacheState.mon.y + CacheState.mon.h;
347  break;
348  case WL_SOUTH_WEST:
349  state->y = CacheState.mon.y + CacheState.mon.h;
350  /* FALLTHRU */
351  case WL_WEST:
352  state->x = CacheState.mon.x;
353  break;
354  case WL_CENTER:;
355  /* FALLTHRU */
356  default:
357  break;
358  }
359  switch (anchor) {
360  case WL_SOUTH_WEST:
361  state->y -= state->height;
362  break;
363  case WL_SOUTH:
364  state->x -= state->width / 2;
365  state->y -= state->height;
366  break;
367  case WL_SOUTH_EAST:
368  state->x -= state->width;
369  state->y -= state->height;
370  break;
371  case WL_NORTH_EAST:
372  state->x -= state->width;
373  break;
374  case WL_NORTH_WEST:
375  break;
376  case WL_NORTH:
377  state->x -= state->width / 2;
378  break;
379  case WL_EAST:
380  state->x -= state->width;
381  state->y -= state->height / 2;
382  break;
383  case WL_WEST:
384  state->y -= state->height / 2;
385  break;
386  case WL_CENTER:
387  state->y -= state->height / 2;
388  state->x -= state->width / 2;
389  break;
390  default:
391  break;
392  }
393  // Apply offset.
395  "x-offset", config.x_offset);
397  "y-offset", config.y_offset);
400 }
401 
403  if (state == NULL) {
404  return;
405  }
406  uint16_t mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y |
407  XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
408  uint32_t vals[] = {state->x, state->y, state->width, state->height};
409 
410  // Display it.
411  xcb_configure_window(xcb->connection, CacheState.main_window, mask, vals);
412  cairo_destroy(CacheState.edit_draw);
413  cairo_surface_destroy(CacheState.edit_surf);
414 
415  xcb_free_pixmap(xcb->connection, CacheState.edit_pixmap);
416  CacheState.edit_pixmap = xcb_generate_id(xcb->connection);
417  xcb_create_pixmap(xcb->connection, depth->depth, CacheState.edit_pixmap,
418  CacheState.main_window, state->width, state->height);
419 
420  CacheState.edit_surf =
421  cairo_xcb_surface_create(xcb->connection, CacheState.edit_pixmap, visual,
422  state->width, state->height);
423  CacheState.edit_draw = cairo_create(CacheState.edit_surf);
424 
425  g_debug("Re-size window based internal request: %dx%d.", state->width,
426  state->height);
427  // Should wrap main window in a widget.
428  widget_resize(WIDGET(state->main_window), state->width, state->height);
429 }
430 
431 extern GList *list_of_warning_msgs;
433  if (state->mesg_box == NULL) {
434  return;
435  }
436  char *msg = mode_get_message(state->sw);
437  if (msg || list_of_warning_msgs) {
440  GString *emesg = g_string_new(msg);
441  if (list_of_warning_msgs) {
442  if (msg) {
443  g_string_append_c(emesg, '\n');
444  }
445  g_string_append(
446  emesg, "The following warnings were detected when starting rofi:\n");
447  GList *iter = g_list_first(list_of_warning_msgs);
448  int index = 0;
449  for (; iter != NULL && index < 2; iter = g_list_next(iter)) {
450  GString *msg = (GString *)(iter->data);
451  g_string_append(emesg, "\n\n");
452  g_string_append(emesg, msg->str);
453  index++;
454  }
455  if (g_list_length(iter) > 1) {
456  g_string_append_printf(emesg, "\nThere are <b>%u</b> more errors.",
457  g_list_length(iter) - 1);
458  }
459  }
460  textbox_text(state->mesg_tb, emesg->str);
461  widget_enable(WIDGET(state->mesg_box));
462  g_string_free(emesg, TRUE);
463  g_free(msg);
464  } else {
465  widget_disable(WIDGET(state->mesg_box));
466  }
467 }
468 
469 static gboolean rofi_view_reload_idle(G_GNUC_UNUSED gpointer data) {
470  if (current_active_menu) {
471  // For UI update on this.
473  char *r =
474  g_strdup_printf("%u", mode_get_num_entries(current_active_menu->sw));
476  g_free(r);
477  }
478  current_active_menu->reload = TRUE;
481  }
482  CacheState.idle_timeout = 0;
483  return G_SOURCE_REMOVE;
484 }
485 
486 static void rofi_view_take_action(const char *name) {
487  ThemeWidget *wid = rofi_config_find_widget(name, NULL, TRUE);
488  if (wid) {
490  Property *p = rofi_theme_find_property(wid, P_STRING, "action", TRUE);
491  if (p != NULL && p->type == P_STRING) {
492  const char *action = p->value.s;
493  guint id = key_binding_get_action_from_name(action);
494  if (id != UINT32_MAX) {
496  } else {
497  g_warning("Failed to parse keybinding: %s\r\n", action);
498  }
499  }
500  }
501 }
502 static gboolean rofi_view_user_timeout(G_GNUC_UNUSED gpointer data) {
503  CacheState.user_timeout = 0;
504  rofi_view_take_action("timeout");
505  return G_SOURCE_REMOVE;
506 }
507 
508 static void rofi_view_set_user_timeout(G_GNUC_UNUSED gpointer data) {
509  if (CacheState.user_timeout > 0) {
510  g_source_remove(CacheState.user_timeout);
511  CacheState.user_timeout = 0;
512  }
513  {
515  ThemeWidget *wid = rofi_config_find_widget("timeout", NULL, TRUE);
516  if (wid) {
518  Property *p = rofi_theme_find_property(wid, P_INTEGER, "delay", TRUE);
519  if (p != NULL && p->type == P_INTEGER && p->value.i > 0) {
520  int delay = p->value.i;
521  CacheState.user_timeout =
522  g_timeout_add(delay * 1000, rofi_view_user_timeout, NULL);
523  }
524  }
525  }
526 }
527 
528 void rofi_view_reload(void) {
529  // @TODO add check if current view is equal to the callee
530  if (CacheState.idle_timeout == 0) {
531  CacheState.idle_timeout =
532  g_timeout_add(1000 / 100, rofi_view_reload_idle, NULL);
533  }
534 }
536  if (current_active_menu && CacheState.repaint_source == 0) {
537  CacheState.count++;
538  g_debug("redraw %llu", CacheState.count);
539  CacheState.repaint_source =
540  g_idle_add_full(G_PRIORITY_HIGH_IDLE, rofi_view_repaint, NULL, NULL);
541  }
542 }
543 
545  state->quit = FALSE;
546  state->retv = MENU_CANCEL;
547 }
548 
550 
552  if (state == current_active_menu) {
553  rofi_view_set_active(NULL);
554  } else if (state) {
555  g_queue_remove(&(CacheState.views), state);
556  }
557 }
559  if (current_active_menu != NULL && state != NULL) {
560  g_queue_push_head(&(CacheState.views), current_active_menu);
561  // TODO check.
562  current_active_menu = state;
563  g_debug("stack view.");
566  return;
567  }
568  if (state == NULL && !g_queue_is_empty(&(CacheState.views))) {
569  g_debug("pop view.");
570  current_active_menu = g_queue_pop_head(&(CacheState.views));
573  return;
574  }
575  g_assert((current_active_menu == NULL && state != NULL) ||
576  (current_active_menu != NULL && state == NULL));
577  current_active_menu = state;
579 }
580 
582  unsigned int selected_line) {
583  state->selected_line = selected_line;
584  // Find the line.
585  unsigned int selected = 0;
586  for (unsigned int i = 0; ((state->selected_line)) < UINT32_MAX && !selected &&
587  i < state->filtered_lines;
588  i++) {
589  if (state->line_map[i] == (state->selected_line)) {
590  selected = i;
591  break;
592  }
593  }
594  listview_set_selected(state->list_view, selected);
595  xcb_clear_area(xcb->connection, CacheState.main_window, 1, 0, 0, 1, 1);
596  xcb_flush(xcb->connection);
597 }
598 
600  if (state->tokens) {
602  state->tokens = NULL;
603  }
604  // Do this here?
605  // Wait for final release?
606  widget_free(WIDGET(state->main_window));
607 
608  g_free(state->line_map);
609  g_free(state->distance);
610  // Free the switcher boxes.
611  // When state is free'ed we should no longer need these.
612  g_free(state->modes);
613  state->num_modes = 0;
614  g_free(state);
615 }
616 
618  return state->retv;
619 }
620 
621 unsigned int rofi_view_get_selected_line(const RofiViewState *state) {
622  return state->selected_line;
623 }
624 
625 unsigned int rofi_view_get_next_position(const RofiViewState *state) {
626  unsigned int next_pos = state->selected_line;
627  unsigned int selected = listview_get_selected(state->list_view);
628  if ((selected + 1) < state->num_lines) {
629  (next_pos) = state->line_map[selected + 1];
630  }
631  return next_pos;
632 }
633 
634 unsigned int rofi_view_get_completed(const RofiViewState *state) {
635  return state->quit;
636 }
637 
638 const char *rofi_view_get_user_input(const RofiViewState *state) {
639  if (state->text) {
640  return state->text->text;
641  }
642  return NULL;
643 }
644 
651  return g_malloc0(sizeof(RofiViewState));
652 }
653 
657 typedef struct _thread_state_view {
660 
662  GCond *cond;
664  GMutex *mutex;
666  unsigned int *acount;
667 
671  unsigned int start;
673  unsigned int stop;
675  unsigned int count;
676 
678  const char *pattern;
680  glong plen;
688 static void rofi_view_call_thread(gpointer data, gpointer user_data) {
689  thread_state *t = (thread_state *)data;
690  t->callback(t, user_data);
691 }
692 
694  G_GNUC_UNUSED gpointer user_data) {
696  for (unsigned int i = t->start; i < t->stop; i++) {
697  int match = mode_token_match(t->state->sw, t->state->tokens, i);
698  // If each token was matched, add it to list.
699  if (match) {
700  t->state->line_map[t->start + t->count] = i;
701  if (config.sort) {
702  // This is inefficient, need to fix it.
703  char *str = mode_get_completion(t->state->sw, i);
704  glong slen = g_utf8_strlen(str, -1);
705  switch (config.sorting_method_enum) {
706  case SORT_FZF:
707  t->state->distance[i] =
708  rofi_scorer_fuzzy_evaluate(t->pattern, t->plen, str, slen);
709  break;
710  case SORT_NORMAL:
711  default:
712  t->state->distance[i] = levenshtein(t->pattern, t->plen, str, slen);
713  break;
714  }
715  g_free(str);
716  }
717  t->count++;
718  }
719  }
720  if (t->acount != NULL) {
721  g_mutex_lock(t->mutex);
722  (*(t->acount))--;
723  g_cond_signal(t->cond);
724  g_mutex_unlock(t->mutex);
725  }
726 }
727 
728 static void
730  const char *const fake_background) {
731  if (CacheState.fake_bg == NULL) {
732  cairo_surface_t *s = NULL;
737  TICK_N("Fake start");
738  if (g_strcmp0(fake_background, "real") == 0) {
739  return;
740  }
741  if (g_strcmp0(fake_background, "screenshot") == 0) {
743  } else if (g_strcmp0(fake_background, "background") == 0) {
745  } else {
746  char *fpath = rofi_expand_path(fake_background);
747  g_debug("Opening %s to use as background.", fpath);
748  s = cairo_image_surface_create_from_png(fpath);
749  CacheState.fake_bgrel = TRUE;
750  g_free(fpath);
751  }
752  TICK_N("Get surface.");
753  if (s != NULL) {
754  if (cairo_surface_status(s) != CAIRO_STATUS_SUCCESS) {
755  g_debug("Failed to open surface fake background: %s",
756  cairo_status_to_string(cairo_surface_status(s)));
757  cairo_surface_destroy(s);
758  s = NULL;
759  } else {
760  CacheState.fake_bg = cairo_image_surface_create(
761  CAIRO_FORMAT_ARGB32, CacheState.mon.w, CacheState.mon.h);
762 
763  int blur = rofi_theme_get_integer(WIDGET(win), "blur", 0);
764  cairo_t *dr = cairo_create(CacheState.fake_bg);
765  if (CacheState.fake_bgrel) {
766  cairo_set_source_surface(dr, s, 0, 0);
767  } else {
768  cairo_set_source_surface(dr, s, -CacheState.mon.x, -CacheState.mon.y);
769  }
770  cairo_paint(dr);
771  cairo_destroy(dr);
772  cairo_surface_destroy(s);
773  if (blur > 0) {
774  cairo_image_surface_blur(CacheState.fake_bg, (double)blur, 0);
775  TICK_N("BLUR");
776  }
777  }
778  }
779  TICK_N("Fake transparency");
780  }
781 }
782 void __create_window(MenuFlags menu_flags) {
783  uint32_t selmask = XCB_CW_BACK_PIXMAP | XCB_CW_BORDER_PIXEL |
784  XCB_CW_BIT_GRAVITY | XCB_CW_BACKING_STORE |
785  XCB_CW_EVENT_MASK | XCB_CW_COLORMAP;
786  uint32_t xcb_event_masks =
787  XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS |
788  XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_KEY_PRESS |
789  XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_KEYMAP_STATE |
790  XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_FOCUS_CHANGE |
791  XCB_EVENT_MASK_BUTTON_1_MOTION | XCB_EVENT_MASK_POINTER_MOTION;
792 
793  uint32_t selval[] = {XCB_BACK_PIXMAP_NONE, 0,
794  XCB_GRAVITY_STATIC, XCB_BACKING_STORE_NOT_USEFUL,
795  xcb_event_masks, map};
796 
797  xcb_window_t box_window = xcb_generate_id(xcb->connection);
798  xcb_void_cookie_t cc = xcb_create_window_checked(
799  xcb->connection, depth->depth, box_window, xcb_stuff_get_root_window(), 0,
800  0, 200, 100, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, visual->visual_id, selmask,
801  selval);
802  xcb_generic_error_t *error;
803  error = xcb_request_check(xcb->connection, cc);
804  if (error) {
805  g_error("xcb_create_window() failed error=0x%x\n", error->error_code);
806  exit(EXIT_FAILURE);
807  }
808  TICK_N("xcb create window");
809  CacheState.gc = xcb_generate_id(xcb->connection);
810  xcb_create_gc(xcb->connection, CacheState.gc, box_window, 0, 0);
811 
812  TICK_N("xcb create gc");
813  // Create a drawable.
814  CacheState.edit_pixmap = xcb_generate_id(xcb->connection);
815  xcb_create_pixmap(xcb->connection, depth->depth, CacheState.edit_pixmap,
816  CacheState.main_window, 200, 100);
817 
818  CacheState.edit_surf = cairo_xcb_surface_create(
819  xcb->connection, CacheState.edit_pixmap, visual, 200, 100);
820  CacheState.edit_draw = cairo_create(CacheState.edit_surf);
821 
822  TICK_N("create cairo surface");
823  // Set up pango context.
824  cairo_font_options_t *fo = cairo_font_options_create();
825  // Take font description from xlib surface
826  cairo_surface_get_font_options(CacheState.edit_surf, fo);
827  // TODO should we update the drawable each time?
828  PangoContext *p = pango_cairo_create_context(CacheState.edit_draw);
829  // Set the font options from the xlib surface
830  pango_cairo_context_set_font_options(p, fo);
831  TICK_N("pango cairo font setup");
832 
833  CacheState.main_window = box_window;
834  CacheState.flags = menu_flags;
835  monitor_active(&(CacheState.mon));
836  // Setup dpi
837  if (config.dpi > 1) {
838  PangoFontMap *font_map = pango_cairo_font_map_get_default();
839  pango_cairo_font_map_set_resolution((PangoCairoFontMap *)font_map,
840  (double)config.dpi);
841  } else if (config.dpi == 0 || config.dpi == 1) {
842  // Auto-detect mode.
843  double dpi = 96;
844  if (CacheState.mon.mh > 0 && config.dpi == 1) {
845  dpi = (CacheState.mon.h * 25.4) / (double)(CacheState.mon.mh);
846  } else {
847  dpi = (xcb->screen->height_in_pixels * 25.4) /
848  (double)(xcb->screen->height_in_millimeters);
849  }
850 
851  g_debug("Auto-detected DPI: %.2lf", dpi);
852  PangoFontMap *font_map = pango_cairo_font_map_get_default();
853  pango_cairo_font_map_set_resolution((PangoCairoFontMap *)font_map, dpi);
854  config.dpi = dpi;
855  } else {
856  // default pango is 96.
857  PangoFontMap *font_map = pango_cairo_font_map_get_default();
858  config.dpi =
859  pango_cairo_font_map_get_resolution((PangoCairoFontMap *)font_map);
860  }
861  // Setup font.
862  // Dummy widget.
863  box *win = box_create(NULL, "window", ROFI_ORIENTATION_HORIZONTAL);
864  const char *font =
866  if (font) {
867  PangoFontDescription *pfd = pango_font_description_from_string(font);
868  if (helper_validate_font(pfd, font)) {
869  pango_context_set_font_description(p, pfd);
870  }
871  pango_font_description_free(pfd);
872  }
873  PangoLanguage *l = pango_language_get_default();
874  pango_context_set_language(p, l);
875  TICK_N("configure font");
876 
877  // Tell textbox to use this context.
878  textbox_set_pango_context(font, p);
879  // cleanup
880  g_object_unref(p);
881  cairo_font_options_destroy(fo);
882 
883  TICK_N("textbox setup");
884  // // make it an unmanaged window
885  if (((menu_flags & MENU_NORMAL_WINDOW) == 0)) {
886  window_set_atom_prop(box_window, xcb->ewmh._NET_WM_STATE,
887  &(xcb->ewmh._NET_WM_STATE_ABOVE), 1);
888  uint32_t values[] = {1};
889  xcb_change_window_attributes(xcb->connection, box_window,
890  XCB_CW_OVERRIDE_REDIRECT, values);
891  } else {
892  window_set_atom_prop(box_window, xcb->ewmh._NET_WM_WINDOW_TYPE,
893  &(xcb->ewmh._NET_WM_WINDOW_TYPE_NORMAL), 1);
894  x11_disable_decoration(box_window);
895  }
896 
897  TICK_N("setup window attributes");
898  CacheState.fullscreen =
899  rofi_theme_get_boolean(WIDGET(win), "fullscreen", FALSE);
900  if (CacheState.fullscreen) {
901  xcb_atom_t atoms[] = {xcb->ewmh._NET_WM_STATE_FULLSCREEN,
902  xcb->ewmh._NET_WM_STATE_ABOVE};
903  window_set_atom_prop(box_window, xcb->ewmh._NET_WM_STATE, atoms,
904  sizeof(atoms) / sizeof(xcb_atom_t));
905  }
906 
907  xcb_atom_t protocols[] = {netatoms[WM_TAKE_FOCUS]};
908  xcb_icccm_set_wm_protocols(xcb->connection, box_window,
909  xcb->ewmh.WM_PROTOCOLS, G_N_ELEMENTS(protocols),
910  protocols);
911 
912  TICK_N("setup window fullscreen");
913  // Set the WM_NAME
915  const char wm_class_name[] = "rofi\0Rofi";
916  xcb_icccm_set_wm_class(xcb->connection, box_window, sizeof(wm_class_name),
917  wm_class_name);
918 
919  TICK_N("setup window name and class");
920  const char *transparency =
921  rofi_theme_get_string(WIDGET(win), "transparency", NULL);
922  if (transparency) {
923  rofi_view_setup_fake_transparency(WIDGET(win), transparency);
924  }
925  if (xcb->sncontext != NULL) {
926  sn_launchee_context_setup_window(xcb->sncontext, CacheState.main_window);
927  }
928  TICK_N("setup startup notification");
929  widget_free(WIDGET(win));
930  TICK_N("done");
931 
932  // Set the PID.
933  pid_t pid = getpid();
934  xcb_ewmh_set_wm_pid(&(xcb->ewmh), CacheState.main_window, pid);
935 
936  // Get hostname
937  const char *hostname = g_get_host_name();
938  char *ahost = g_hostname_to_ascii(hostname);
939  if (ahost != NULL) {
940  xcb_icccm_set_wm_client_machine(xcb->connection, CacheState.main_window,
941  XCB_ATOM_STRING, 8, strlen(ahost), ahost);
942  g_free(ahost);
943  }
944 }
945 
952  if (CacheState.fullscreen) {
953  state->width = CacheState.mon.w;
954  return;
955  }
956  // Calculate as float to stop silly, big rounding down errors.
957  state->width = (CacheState.mon.w / 100.0f) * DEFAULT_MENU_WIDTH;
958  // Use theme configured width, if set.
960  "width", state->width);
962 }
963 
974  if (state->filtered_lines == 1) {
975  state->retv = MENU_OK;
976  (state->selected_line) =
977  state->line_map[listview_get_selected(state->list_view)];
978  state->quit = 1;
979  return;
980  }
981 
982  // Double tab!
983  if (state->filtered_lines == 0 && ROW_TAB == state->prev_action) {
984  state->retv = MENU_NEXT;
985  (state->selected_line) = 0;
986  state->quit = TRUE;
987  } else {
989  }
990  state->prev_action = ROW_TAB;
991 }
997 inline static void rofi_view_nav_row_select(RofiViewState *state) {
998  if (state->list_view == NULL) {
999  return;
1000  }
1001  unsigned int selected = listview_get_selected(state->list_view);
1002  // If a valid item is selected, return that..
1003  if (selected < state->filtered_lines) {
1004  char *str = mode_get_completion(state->sw, state->line_map[selected]);
1005  textbox_text(state->text, str);
1006  g_free(str);
1007  textbox_keybinding(state->text, MOVE_END);
1008  state->refilter = TRUE;
1009  }
1010 }
1011 
1017 inline static void rofi_view_nav_first(RofiViewState *state) {
1018  // state->selected = 0;
1019  listview_set_selected(state->list_view, 0);
1020 }
1021 
1027 inline static void rofi_view_nav_last(RofiViewState *state) {
1028  // If no lines, do nothing.
1029  if (state->filtered_lines == 0) {
1030  return;
1031  }
1032  // state->selected = state->filtered_lines - 1;
1033  listview_set_selected(state->list_view, -1);
1034 }
1035 static void selection_changed_callback(G_GNUC_UNUSED listview *lv,
1036  unsigned int index, void *udata) {
1037  RofiViewState *state = (RofiViewState *)udata;
1038  if (state->tb_current_entry) {
1039  if (index < state->filtered_lines) {
1040  int fstate = 0;
1041  char *text = mode_get_display_value(state->sw, state->line_map[index],
1042  &fstate, NULL, TRUE);
1043  textbox_text(state->tb_current_entry, text);
1044  g_free(text);
1045 
1046  } else {
1047  textbox_text(state->tb_current_entry, "");
1048  }
1049  }
1050  if (state->icon_current_entry) {
1051  if (index < state->filtered_lines) {
1052  int icon_height =
1054  WIDGET(state->icon_current_entry)->w);
1055  cairo_surface_t *icon =
1056  mode_get_icon(state->sw, state->line_map[index], icon_height);
1058  } else {
1059  icon_set_surface(state->icon_current_entry, NULL);
1060  }
1061  }
1062 }
1063 static void update_callback(textbox *t, icon *ico, unsigned int index,
1064  void *udata, TextBoxFontType *type, gboolean full) {
1065  RofiViewState *state = (RofiViewState *)udata;
1066  if (full) {
1067  GList *add_list = NULL;
1068  int fstate = 0;
1069  char *text = mode_get_display_value(state->sw, state->line_map[index],
1070  &fstate, &add_list, TRUE);
1071  (*type) |= fstate;
1072 
1073  if (ico) {
1074  int icon_height = widget_get_desired_height(WIDGET(ico), WIDGET(ico)->w);
1075  cairo_surface_t *icon =
1076  mode_get_icon(state->sw, state->line_map[index], icon_height);
1077  icon_set_surface(ico, icon);
1078  }
1079  if (t) {
1080  // TODO needed for markup.
1081  textbox_font(t, *type);
1082  // Move into list view.
1083  textbox_text(t, text);
1084  PangoAttrList *list = textbox_get_pango_attributes(t);
1085  if (list != NULL) {
1086  pango_attr_list_ref(list);
1087  } else {
1088  list = pango_attr_list_new();
1089  }
1090 
1091  if (state->tokens) {
1093  {0.0, 0.0, 0.0, 0.0}};
1094  th = rofi_theme_get_highlight(WIDGET(t), "highlight", th);
1096  textbox_get_visible_text(t), list);
1097  }
1098  for (GList *iter = g_list_first(add_list); iter != NULL;
1099  iter = g_list_next(iter)) {
1100  pango_attr_list_insert(list, (PangoAttribute *)(iter->data));
1101  }
1103  pango_attr_list_unref(list);
1104  }
1105  g_list_free(add_list);
1106  g_free(text);
1107  } else {
1108  // Never called.
1109  int fstate = 0;
1110  mode_get_display_value(state->sw, state->line_map[index], &fstate, NULL,
1111  FALSE);
1112  (*type) |= fstate;
1113  // TODO needed for markup.
1114  textbox_font(t, *type);
1115  }
1116 }
1117 
1118 void rofi_view_update(RofiViewState *state, gboolean qr) {
1119  if (!widget_need_redraw(WIDGET(state->main_window))) {
1120  return;
1121  }
1122  g_debug("Redraw view");
1123  TICK();
1124  cairo_t *d = CacheState.edit_draw;
1125  cairo_set_operator(d, CAIRO_OPERATOR_SOURCE);
1126  if (CacheState.fake_bg != NULL) {
1127  if (CacheState.fake_bgrel) {
1128  cairo_set_source_surface(d, CacheState.fake_bg, 0.0, 0.0);
1129  } else {
1130  cairo_set_source_surface(d, CacheState.fake_bg,
1131  -(double)(state->x - CacheState.mon.x),
1132  -(double)(state->y - CacheState.mon.y));
1133  }
1134  cairo_paint(d);
1135  cairo_set_operator(d, CAIRO_OPERATOR_OVER);
1136  } else {
1137  // Paint the background transparent.
1138  cairo_set_source_rgba(d, 0, 0, 0, 0.0);
1139  cairo_paint(d);
1140  }
1141  TICK_N("Background");
1142 
1143  // Always paint as overlay over the background.
1144  cairo_set_operator(d, CAIRO_OPERATOR_OVER);
1145  widget_draw(WIDGET(state->main_window), d);
1146 
1147  TICK_N("widgets");
1148  cairo_surface_flush(CacheState.edit_surf);
1149  if (qr) {
1151  }
1152 }
1153 
1155  g_free(state->line_map);
1156  g_free(state->distance);
1157  state->num_lines = mode_get_num_entries(state->sw);
1158  state->line_map = g_malloc0_n(state->num_lines, sizeof(unsigned int));
1159  state->distance = g_malloc0_n(state->num_lines, sizeof(int));
1160  listview_set_max_lines(state->list_view, state->num_lines);
1162 }
1163 
1164 static gboolean rofi_view_refilter_real(RofiViewState *state) {
1165  CacheState.refilter_timeout = 0;
1166  CacheState.refilter_timeout_count = 0;
1167  if (state->sw == NULL) {
1168  return G_SOURCE_REMOVE;
1169  }
1170  TICK_N("Filter start");
1171  if (state->reload) {
1172  _rofi_view_reload_row(state);
1173  state->reload = FALSE;
1174  }
1175  TICK_N("Filter reload rows");
1176  if (state->tokens) {
1177  helper_tokenize_free(state->tokens);
1178  state->tokens = NULL;
1179  }
1180  TICK_N("Filter tokenize");
1181  if (state->text && strlen(state->text->text) > 0) {
1182 
1183  listview_set_filtered(state->list_view, TRUE);
1184  unsigned int j = 0;
1185  gchar *pattern = mode_preprocess_input(state->sw, state->text->text);
1186  glong plen = pattern ? g_utf8_strlen(pattern, -1) : 0;
1187  state->tokens = helper_tokenize(pattern, config.case_sensitive);
1195  unsigned int nt = MAX(1, state->num_lines / 500);
1196  // Limit the number of jobs, it could cause stack overflow if we don´t
1197  // limit.
1198  nt = MIN(nt, config.threads * 4);
1199  thread_state_view states[nt];
1200  GCond cond;
1201  GMutex mutex;
1202  g_mutex_init(&mutex);
1203  g_cond_init(&cond);
1204  unsigned int count = nt;
1205  unsigned int steps = (state->num_lines + nt) / nt;
1206  for (unsigned int i = 0; i < nt; i++) {
1207  states[i].state = state;
1208  states[i].start = i * steps;
1209  states[i].stop = MIN(state->num_lines, (i + 1) * steps);
1210  states[i].count = 0;
1211  states[i].cond = &cond;
1212  states[i].mutex = &mutex;
1213  states[i].acount = &count;
1214  states[i].plen = plen;
1215  states[i].pattern = pattern;
1216  states[i].st.callback = filter_elements;
1217  if (i > 0) {
1218  g_thread_pool_push(tpool, &states[i], NULL);
1219  }
1220  }
1221  // Run one in this thread.
1222  rofi_view_call_thread(&states[0], NULL);
1223  // No need to do this with only one thread.
1224  if (nt > 1) {
1225  g_mutex_lock(&mutex);
1226  while (count > 0) {
1227  g_cond_wait(&cond, &mutex);
1228  }
1229  g_mutex_unlock(&mutex);
1230  }
1231  g_cond_clear(&cond);
1232  g_mutex_clear(&mutex);
1233  for (unsigned int i = 0; i < nt; i++) {
1234  if (j != states[i].start) {
1235  memmove(&(state->line_map[j]), &(state->line_map[states[i].start]),
1236  sizeof(unsigned int) * (states[i].count));
1237  }
1238  j += states[i].count;
1239  }
1240  if (config.sort) {
1241  g_qsort_with_data(state->line_map, j, sizeof(int), lev_sort,
1242  state->distance);
1243  }
1244 
1245  // Cleanup + bookkeeping.
1246  state->filtered_lines = j;
1247  g_free(pattern);
1248  } else {
1249  listview_set_filtered(state->list_view, FALSE);
1250  for (unsigned int i = 0; i < state->num_lines; i++) {
1251  state->line_map[i] = i;
1252  }
1253  state->filtered_lines = state->num_lines;
1254  }
1255  TICK_N("Filter matching done");
1257 
1258  if (state->tb_filtered_rows) {
1259  char *r = g_strdup_printf("%u", state->filtered_lines);
1260  textbox_text(state->tb_filtered_rows, r);
1261  g_free(r);
1262  }
1263  if (state->tb_total_rows) {
1264  char *r = g_strdup_printf("%u", state->num_lines);
1265  textbox_text(state->tb_total_rows, r);
1266  g_free(r);
1267  }
1268  TICK_N("Update filter lines");
1269 
1270  if (config.auto_select == TRUE && state->filtered_lines == 1 &&
1271  state->num_lines > 1) {
1272  (state->selected_line) =
1273  state->line_map[listview_get_selected(state->list_view)];
1274  state->retv = MENU_OK;
1275  state->quit = TRUE;
1276  }
1277 
1278  // Size the window.
1279  int height = rofi_view_calculate_height(state);
1280  if (height != state->height) {
1281  state->height = height;
1284  g_debug("Resize based on re-filter");
1285  }
1286  TICK_N("Filter resize window based on window ");
1287  state->refilter = FALSE;
1288  TICK_N("Filter done");
1289  rofi_view_update(state, TRUE);
1290  return G_SOURCE_REMOVE;
1291 }
1292 static void rofi_view_refilter(RofiViewState *state) {
1293  CacheState.refilter_timeout_count++;
1294  if (CacheState.refilter_timeout != 0) {
1295 
1296  g_source_remove(CacheState.refilter_timeout);
1297  CacheState.refilter_timeout = 0;
1298  }
1299  if (state->num_lines > config.refilter_timeout_limit &&
1300  CacheState.refilter_timeout_count < 25 && state->text &&
1301  strlen(state->text->text) > 0) {
1302  CacheState.refilter_timeout =
1303  g_timeout_add(200, (GSourceFunc)rofi_view_refilter_real, state);
1304  } else {
1305  rofi_view_refilter_real(state);
1306  }
1307 }
1309  if (CacheState.refilter_timeout != 0) {
1310  g_source_remove(CacheState.refilter_timeout);
1311  CacheState.refilter_timeout = 0;
1312  }
1313  if (state->refilter) {
1314  rofi_view_refilter_real(state);
1315  }
1316 }
1322 void process_result(RofiViewState *state);
1324  if (state && state->finalize != NULL) {
1325  state->finalize(state);
1326  }
1327 }
1328 
1333 static void rofi_view_input_changed() { rofi_view_take_action("inputchange"); }
1334 
1337  switch (action) {
1338  // Handling of paste
1339  case PASTE_PRIMARY:
1340  xcb_convert_selection(xcb->connection, CacheState.main_window,
1341  XCB_ATOM_PRIMARY, xcb->ewmh.UTF8_STRING,
1342  xcb->ewmh.UTF8_STRING, XCB_CURRENT_TIME);
1343  xcb_flush(xcb->connection);
1344  break;
1345  case PASTE_SECONDARY:
1346  xcb_convert_selection(xcb->connection, CacheState.main_window,
1347  netatoms[CLIPBOARD], xcb->ewmh.UTF8_STRING,
1348  xcb->ewmh.UTF8_STRING, XCB_CURRENT_TIME);
1349  xcb_flush(xcb->connection);
1350  break;
1351  case SCREENSHOT:
1353  break;
1354  case CHANGE_ELLIPSIZE:
1355  if (state->list_view) {
1357  }
1358  break;
1359  case TOGGLE_SORT:
1360  if (state->case_indicator != NULL) {
1361  config.sort = !config.sort;
1362  state->refilter = TRUE;
1364  }
1365  break;
1366  case MODE_PREVIOUS:
1367  state->retv = MENU_PREVIOUS;
1368  (state->selected_line) = 0;
1369  state->quit = TRUE;
1370  break;
1371  // Menu navigation.
1372  case MODE_NEXT:
1373  state->retv = MENU_NEXT;
1374  (state->selected_line) = 0;
1375  state->quit = TRUE;
1376  break;
1377  case MODE_COMPLETE: {
1378  unsigned int selected = listview_get_selected(state->list_view);
1379  state->selected_line = UINT32_MAX;
1380  if (selected < state->filtered_lines) {
1381  state->selected_line = state->line_map[selected];
1382  }
1383  state->retv = MENU_COMPLETE;
1384  state->quit = TRUE;
1385  break;
1386  }
1387  // Toggle case sensitivity.
1389  if (state->case_indicator != NULL) {
1391  (state->selected_line) = 0;
1392  state->refilter = TRUE;
1394  }
1395  break;
1396  // Special delete entry command.
1397  case DELETE_ENTRY: {
1398  unsigned int selected = listview_get_selected(state->list_view);
1399  if (selected < state->filtered_lines) {
1400  (state->selected_line) = state->line_map[selected];
1401  state->retv = MENU_ENTRY_DELETE;
1402  state->quit = TRUE;
1403  }
1404  break;
1405  }
1406  case SELECT_ELEMENT_1:
1407  case SELECT_ELEMENT_2:
1408  case SELECT_ELEMENT_3:
1409  case SELECT_ELEMENT_4:
1410  case SELECT_ELEMENT_5:
1411  case SELECT_ELEMENT_6:
1412  case SELECT_ELEMENT_7:
1413  case SELECT_ELEMENT_8:
1414  case SELECT_ELEMENT_9:
1415  case SELECT_ELEMENT_10: {
1416  unsigned int index = action - SELECT_ELEMENT_1;
1417  if (index < state->filtered_lines) {
1418  state->selected_line = state->line_map[index];
1419  state->retv = MENU_OK;
1420  state->quit = TRUE;
1421  }
1422  break;
1423  }
1424  case CUSTOM_1:
1425  case CUSTOM_2:
1426  case CUSTOM_3:
1427  case CUSTOM_4:
1428  case CUSTOM_5:
1429  case CUSTOM_6:
1430  case CUSTOM_7:
1431  case CUSTOM_8:
1432  case CUSTOM_9:
1433  case CUSTOM_10:
1434  case CUSTOM_11:
1435  case CUSTOM_12:
1436  case CUSTOM_13:
1437  case CUSTOM_14:
1438  case CUSTOM_15:
1439  case CUSTOM_16:
1440  case CUSTOM_17:
1441  case CUSTOM_18:
1442  case CUSTOM_19: {
1443  state->selected_line = UINT32_MAX;
1444  unsigned int selected = listview_get_selected(state->list_view);
1445  if (selected < state->filtered_lines) {
1446  (state->selected_line) = state->line_map[selected];
1447  }
1448  state->retv = MENU_CUSTOM_COMMAND | ((action - CUSTOM_1) & MENU_LOWER_MASK);
1449  state->quit = TRUE;
1450  break;
1451  }
1452  // If you add a binding here, make sure to add it to
1453  // rofi_view_keyboard_navigation too
1454  case CANCEL:
1455  state->retv = MENU_CANCEL;
1456  state->quit = TRUE;
1457  break;
1458  case ELEMENT_NEXT:
1459  listview_nav_next(state->list_view);
1460  break;
1461  case ELEMENT_PREV:
1462  listview_nav_prev(state->list_view);
1463  break;
1464  case ROW_UP:
1465  listview_nav_up(state->list_view);
1466  break;
1467  case ROW_TAB:
1468  rofi_view_nav_row_tab(state);
1469  break;
1470  case ROW_DOWN:
1471  listview_nav_down(state->list_view);
1472  break;
1473  case ROW_LEFT:
1474  listview_nav_left(state->list_view);
1475  break;
1476  case ROW_RIGHT:
1477  listview_nav_right(state->list_view);
1478  break;
1479  case PAGE_PREV:
1481  break;
1482  case PAGE_NEXT:
1484  break;
1485  case ROW_FIRST:
1486  rofi_view_nav_first(state);
1487  break;
1488  case ROW_LAST:
1489  rofi_view_nav_last(state);
1490  break;
1491  case ROW_SELECT:
1492  rofi_view_nav_row_select(state);
1493  break;
1494  // If you add a binding here, make sure to add it to textbox_keybinding too
1495  case MOVE_CHAR_BACK: {
1496  if (textbox_keybinding(state->text, action) == 0) {
1497  listview_nav_left(state->list_view);
1498  }
1499  break;
1500  }
1501  case MOVE_CHAR_FORWARD: {
1502  if (textbox_keybinding(state->text, action) == 0) {
1503  listview_nav_right(state->list_view);
1504  }
1505  break;
1506  }
1507  case CLEAR_LINE:
1508  case MOVE_FRONT:
1509  case MOVE_END:
1510  case REMOVE_TO_EOL:
1511  case REMOVE_TO_SOL:
1512  case REMOVE_WORD_BACK:
1513  case REMOVE_WORD_FORWARD:
1514  case REMOVE_CHAR_FORWARD:
1515  case MOVE_WORD_BACK:
1516  case MOVE_WORD_FORWARD:
1517  case REMOVE_CHAR_BACK: {
1518  int rc = textbox_keybinding(state->text, action);
1519  if (rc == 1) {
1520  // Entry changed.
1521  state->refilter = TRUE;
1523  } else if (rc == 2) {
1524  // Movement.
1525  }
1526  break;
1527  }
1528  case ACCEPT_ALT: {
1529  rofi_view_refilter_force(state);
1530  unsigned int selected = listview_get_selected(state->list_view);
1531  state->selected_line = UINT32_MAX;
1532  if (selected < state->filtered_lines) {
1533  (state->selected_line) = state->line_map[selected];
1534  state->retv = MENU_OK;
1535  } else {
1536  // Nothing entered and nothing selected.
1537  state->retv = MENU_CUSTOM_INPUT;
1538  }
1539  state->retv |= MENU_CUSTOM_ACTION;
1540  state->quit = TRUE;
1541  break;
1542  }
1543  case ACCEPT_CUSTOM: {
1544  rofi_view_refilter_force(state);
1545  state->selected_line = UINT32_MAX;
1546  state->retv = MENU_CUSTOM_INPUT;
1547  state->quit = TRUE;
1548  break;
1549  }
1550  case ACCEPT_CUSTOM_ALT: {
1551  rofi_view_refilter_force(state);
1552  state->selected_line = UINT32_MAX;
1554  state->quit = TRUE;
1555  break;
1556  }
1557  case ACCEPT_ENTRY: {
1558  rofi_view_refilter_force(state);
1559  // If a valid item is selected, return that..
1560  unsigned int selected = listview_get_selected(state->list_view);
1561  state->selected_line = UINT32_MAX;
1562  if (selected < state->filtered_lines) {
1563  (state->selected_line) = state->line_map[selected];
1564  state->retv = MENU_OK;
1565  } else {
1566  // Nothing entered and nothing selected.
1567  state->retv = MENU_CUSTOM_INPUT;
1568  }
1569 
1570  state->quit = TRUE;
1571  break;
1572  }
1573  }
1574 }
1575 
1577  guint action) {
1578  switch (scope) {
1579  case SCOPE_GLOBAL:
1580  return TRUE;
1581  case SCOPE_MOUSE_LISTVIEW:
1583  case SCOPE_MOUSE_EDITBOX:
1584  case SCOPE_MOUSE_SCROLLBAR:
1586  gint x = state->mouse.x, y = state->mouse.y;
1588  (WidgetType)scope, x, y);
1589  if (target == NULL) {
1590  return FALSE;
1591  }
1592  widget_xy_to_relative(target, &x, &y);
1593  switch (widget_check_action(target, action, x, y)) {
1595  return FALSE;
1599  return TRUE;
1600  }
1601  break;
1602  }
1603  }
1604  return FALSE;
1605 }
1606 
1608  guint action) {
1610  switch (scope) {
1611  case SCOPE_GLOBAL:
1613  return;
1614  case SCOPE_MOUSE_LISTVIEW:
1616  case SCOPE_MOUSE_EDITBOX:
1617  case SCOPE_MOUSE_SCROLLBAR:
1619  gint x = state->mouse.x, y = state->mouse.y;
1621  (WidgetType)scope, x, y);
1622  if (target == NULL) {
1623  return;
1624  }
1625  widget_xy_to_relative(target, &x, &y);
1626  switch (widget_trigger_action(target, action, x, y)) {
1628  return;
1630  target = NULL;
1631  /* FALLTHRU */
1633  state->mouse.motion_target = target;
1634  /* FALLTHRU */
1636  return;
1637  }
1638  break;
1639  }
1640  }
1641 }
1642 
1643 void rofi_view_handle_text(RofiViewState *state, char *text) {
1644  if (textbox_append_text(state->text, text, strlen(text))) {
1645  state->refilter = TRUE;
1647  }
1648 }
1649 
1651  switch (type) {
1652  case ROFI_CURSOR_DEFAULT:
1653  return CURSOR_DEFAULT;
1654 
1655  case ROFI_CURSOR_POINTER:
1656  return CURSOR_POINTER;
1657 
1658  case ROFI_CURSOR_TEXT:
1659  return CURSOR_TEXT;
1660  }
1661 
1662  return CURSOR_DEFAULT;
1663 }
1664 
1666  gint y) {
1668  WIDGET_TYPE_UNKNOWN, x, y);
1669 
1670  return target != NULL ? target->cursor_type : ROFI_CURSOR_DEFAULT;
1671 }
1672 
1675 
1676  if (x11_type == CacheState.cursor_type) {
1677  return;
1678  }
1679 
1680  CacheState.cursor_type = x11_type;
1681 
1682  x11_set_cursor(CacheState.main_window, x11_type);
1683 }
1684 
1685 void rofi_view_handle_mouse_motion(RofiViewState *state, gint x, gint y,
1686  gboolean find_mouse_target) {
1687  state->mouse.x = x;
1688  state->mouse.y = y;
1689 
1691 
1693 
1694  if (find_mouse_target) {
1695  widget *target = widget_find_mouse_target(
1697 
1698  if (target != NULL) {
1699  state->mouse.motion_target = target;
1700  }
1701  }
1702 
1703  if (state->mouse.motion_target != NULL) {
1704  widget_xy_to_relative(state->mouse.motion_target, &x, &y);
1706 
1707  if (find_mouse_target) {
1708  state->mouse.motion_target = NULL;
1709  }
1710  }
1711 }
1712 
1714  if (rofi_view_get_completed(state)) {
1715  // This menu is done.
1716  rofi_view_finalize(state);
1717  // If there a state. (for example error) reload it.
1718  state = rofi_view_get_active();
1719 
1720  // cleanup, if no more state to display.
1721  if (state == NULL) {
1722  // Quit main-loop.
1724  return;
1725  }
1726  }
1727 
1728  // Update if requested.
1729  if (state->refilter) {
1730  rofi_view_refilter(state);
1731  }
1732  rofi_view_update(state, TRUE);
1733  return;
1734 }
1735 
1741  xcb_configure_notify_event_t *xce) {
1742  if (xce->window == CacheState.main_window) {
1743  if (state->x != xce->x || state->y != xce->y) {
1744  state->x = xce->x;
1745  state->y = xce->y;
1747  }
1748  if (state->width != xce->width || state->height != xce->height) {
1749  state->width = xce->width;
1750  state->height = xce->height;
1751 
1752  cairo_destroy(CacheState.edit_draw);
1753  cairo_surface_destroy(CacheState.edit_surf);
1754 
1755  xcb_free_pixmap(xcb->connection, CacheState.edit_pixmap);
1756  CacheState.edit_pixmap = xcb_generate_id(xcb->connection);
1757  xcb_create_pixmap(xcb->connection, depth->depth, CacheState.edit_pixmap,
1758  CacheState.main_window, state->width, state->height);
1759 
1760  CacheState.edit_surf =
1761  cairo_xcb_surface_create(xcb->connection, CacheState.edit_pixmap,
1762  visual, state->width, state->height);
1763  CacheState.edit_draw = cairo_create(CacheState.edit_surf);
1764  g_debug("Re-size window based external request: %d %d", state->width,
1765  state->height);
1766  widget_resize(WIDGET(state->main_window), state->width, state->height);
1767  }
1768  }
1769 }
1770 
1774 void rofi_view_temp_click_to_exit(RofiViewState *state, xcb_window_t target) {
1775  if ((CacheState.flags & MENU_NORMAL_WINDOW) == 0) {
1776  if (target != CacheState.main_window) {
1777  state->quit = TRUE;
1778  state->retv = MENU_CANCEL;
1779  }
1780  }
1781 }
1782 
1784  if (CacheState.repaint_source == 0) {
1785  CacheState.count++;
1786  g_debug("redraw %llu", CacheState.count);
1787  CacheState.repaint_source =
1788  g_idle_add_full(G_PRIORITY_HIGH_IDLE, rofi_view_repaint, NULL, NULL);
1789  }
1790 }
1791 
1793  if (CacheState.fullscreen == TRUE) {
1794  return CacheState.mon.h;
1795  }
1796 
1797  RofiDistance h =
1798  rofi_theme_get_distance(WIDGET(state->main_window), "height", 0);
1799  unsigned int height = distance_get_pixel(h, ROFI_ORIENTATION_VERTICAL);
1800  // If height is set, return it.
1801  if (height > 0) {
1802  return height;
1803  }
1804  // Autosize based on widgets.
1805  widget *main_window = WIDGET(state->main_window);
1807 }
1808 
1810  widget *wid, MouseBindingMouseDefaultAction action, G_GNUC_UNUSED gint x,
1811  G_GNUC_UNUSED gint y, G_GNUC_UNUSED void *user_data) {
1812  RofiViewState *state = (RofiViewState *)user_data;
1813  switch (action) {
1814  case MOUSE_CLICK_DOWN: {
1815  const char *type = rofi_theme_get_string(wid, "action", NULL);
1816  if (type) {
1817  if (state->list_view) {
1818  (state->selected_line) =
1819  state->line_map[listview_get_selected(state->list_view)];
1820  } else {
1821  (state->selected_line) = UINT32_MAX;
1822  }
1823  guint id = key_binding_get_action_from_name(type);
1824  if (id != UINT32_MAX) {
1826  }
1827  state->skip_absorb = TRUE;
1829  }
1830  }
1831  case MOUSE_CLICK_UP:
1832  case MOUSE_DCLICK_DOWN:
1833  case MOUSE_DCLICK_UP:
1834  break;
1835  }
1837 }
1839  widget *wid, MouseBindingMouseDefaultAction action, G_GNUC_UNUSED gint x,
1840  G_GNUC_UNUSED gint y, G_GNUC_UNUSED void *user_data) {
1841  RofiViewState *state = (RofiViewState *)user_data;
1842  unsigned int i;
1843  for (i = 0; i < state->num_modes; i++) {
1844  if (WIDGET(state->modes[i]) == wid) {
1845  break;
1846  }
1847  }
1848  if (i == state->num_modes) {
1850  }
1851 
1852  switch (action) {
1853  case MOUSE_CLICK_DOWN:
1854  state->retv = MENU_QUICK_SWITCH | (i & MENU_LOWER_MASK);
1855  state->quit = TRUE;
1856  state->skip_absorb = TRUE;
1858  case MOUSE_CLICK_UP:
1859  case MOUSE_DCLICK_DOWN:
1860  case MOUSE_DCLICK_UP:
1861  break;
1862  }
1864 }
1865 
1866 // @TODO don't like this construction.
1867 static void rofi_view_listview_mouse_activated_cb(listview *lv, gboolean custom,
1868  void *udata) {
1869  RofiViewState *state = (RofiViewState *)udata;
1870  state->retv = MENU_OK;
1871  if (custom) {
1872  state->retv |= MENU_CUSTOM_ACTION;
1873  }
1874  (state->selected_line) = state->line_map[listview_get_selected(lv)];
1875  // Quit
1876  state->quit = TRUE;
1877  state->skip_absorb = TRUE;
1878 }
1879 
1880 static void rofi_view_add_widget(RofiViewState *state, widget *parent_widget,
1881  const char *name) {
1882  char *defaults = NULL;
1883  widget *wid = NULL;
1884 
1888  if (strcmp(name, "mainbox") == 0) {
1889  wid = (widget *)box_create(parent_widget, name, ROFI_ORIENTATION_VERTICAL);
1890  box_add((box *)parent_widget, WIDGET(wid), TRUE);
1891  if (config.sidebar_mode) {
1892  defaults = "inputbar,message,listview,mode-switcher";
1893  } else {
1894  defaults = "inputbar,message,listview";
1895  }
1896  }
1900  else if (strcmp(name, "inputbar") == 0) {
1901  wid =
1902  (widget *)box_create(parent_widget, name, ROFI_ORIENTATION_HORIZONTAL);
1903  defaults = "prompt,entry,overlay,case-indicator";
1904  box_add((box *)parent_widget, WIDGET(wid), FALSE);
1905  }
1909  else if (strcmp(name, "prompt") == 0) {
1910  if (state->prompt != NULL) {
1911  g_error("Prompt widget can only be added once to the layout.");
1912  return;
1913  }
1914  // Prompt box.
1915  state->prompt =
1916  textbox_create(parent_widget, WIDGET_TYPE_TEXTBOX_TEXT, name,
1917  TB_AUTOWIDTH | TB_AUTOHEIGHT, NORMAL, "", 0, 0);
1918  rofi_view_update_prompt(state);
1919  box_add((box *)parent_widget, WIDGET(state->prompt), FALSE);
1920  defaults = NULL;
1921  } else if (strcmp(name, "num-rows") == 0) {
1922  state->tb_total_rows =
1923  textbox_create(parent_widget, WIDGET_TYPE_TEXTBOX_TEXT, name,
1924  TB_AUTOWIDTH | TB_AUTOHEIGHT, NORMAL, "", 0, 0);
1925  box_add((box *)parent_widget, WIDGET(state->tb_total_rows), FALSE);
1926  defaults = NULL;
1927  } else if (strcmp(name, "num-filtered-rows") == 0) {
1928  state->tb_filtered_rows =
1929  textbox_create(parent_widget, WIDGET_TYPE_TEXTBOX_TEXT, name,
1930  TB_AUTOWIDTH | TB_AUTOHEIGHT, NORMAL, "", 0, 0);
1931  box_add((box *)parent_widget, WIDGET(state->tb_filtered_rows), FALSE);
1932  defaults = NULL;
1933  } else if (strcmp(name, "textbox-current-entry") == 0) {
1934  state->tb_current_entry =
1935  textbox_create(parent_widget, WIDGET_TYPE_TEXTBOX_TEXT, name,
1936  TB_MARKUP | TB_AUTOHEIGHT, NORMAL, "", 0, 0);
1937  box_add((box *)parent_widget, WIDGET(state->tb_current_entry), FALSE);
1938  defaults = NULL;
1939  } else if (strcmp(name, "icon-current-entry") == 0) {
1940  state->icon_current_entry = icon_create(parent_widget, name);
1941  box_add((box *)parent_widget, WIDGET(state->icon_current_entry), FALSE);
1942  defaults = NULL;
1943  }
1947  else if (strcmp(name, "case-indicator") == 0) {
1948  if (state->case_indicator != NULL) {
1949  g_error("Case indicator widget can only be added once to the layout.");
1950  return;
1951  }
1952  state->case_indicator =
1953  textbox_create(parent_widget, WIDGET_TYPE_TEXTBOX_TEXT, name,
1954  TB_AUTOWIDTH | TB_AUTOHEIGHT, NORMAL, "*", 0, 0);
1955  // Add small separator between case indicator and text box.
1956  box_add((box *)parent_widget, WIDGET(state->case_indicator), FALSE);
1958  }
1962  else if (strcmp(name, "entry") == 0) {
1963  if (state->text != NULL) {
1964  g_error("Entry textbox widget can only be added once to the layout.");
1965  return;
1966  }
1967  // Entry box
1968  TextboxFlags tfl = TB_EDITABLE;
1969  tfl |= ((state->menu_flags & MENU_PASSWORD) == MENU_PASSWORD) ? TB_PASSWORD
1970  : 0;
1971  state->text = textbox_create(parent_widget, WIDGET_TYPE_EDITBOX, name,
1972  tfl | TB_AUTOHEIGHT, NORMAL, NULL, 0, 0);
1973  box_add((box *)parent_widget, WIDGET(state->text), TRUE);
1974  }
1978  else if (strcmp(name, "message") == 0) {
1979  if (state->mesg_box != NULL) {
1980  g_error("Message widget can only be added once to the layout.");
1981  return;
1982  }
1983  state->mesg_box = container_create(parent_widget, name);
1984  state->mesg_tb = textbox_create(
1985  WIDGET(state->mesg_box), WIDGET_TYPE_TEXTBOX_TEXT, "textbox",
1986  TB_AUTOHEIGHT | TB_MARKUP | TB_WRAP, NORMAL, NULL, 0, 0);
1987  container_add(state->mesg_box, WIDGET(state->mesg_tb));
1989  box_add((box *)parent_widget, WIDGET(state->mesg_box), FALSE);
1990  }
1994  else if (strcmp(name, "listview") == 0) {
1995  if (state->list_view != NULL) {
1996  g_error("Listview widget can only be added once to the layout.");
1997  return;
1998  }
1999  state->list_view = listview_create(parent_widget, name, update_callback,
2000  state, config.element_height, 0);
2002  state->list_view, selection_changed_callback, (void *)state);
2003  box_add((box *)parent_widget, WIDGET(state->list_view), TRUE);
2004  listview_set_scroll_type(state->list_view, config.scroll_method);
2006  state->list_view, rofi_view_listview_mouse_activated_cb, state);
2007 
2008  int lines = rofi_theme_get_integer(WIDGET(state->list_view), "lines",
2010  listview_set_num_lines(state->list_view, lines);
2011  listview_set_max_lines(state->list_view, state->num_lines);
2012  }
2016  else if (strcmp(name, "mode-switcher") == 0 || strcmp(name, "sidebar") == 0) {
2017  if (state->sidebar_bar != NULL) {
2018  g_error("Mode-switcher can only be added once to the layout.");
2019  return;
2020  }
2021  state->sidebar_bar =
2022  box_create(parent_widget, name, ROFI_ORIENTATION_HORIZONTAL);
2023  box_add((box *)parent_widget, WIDGET(state->sidebar_bar), FALSE);
2025  state->modes = g_malloc0(state->num_modes * sizeof(textbox *));
2026  for (unsigned int j = 0; j < state->num_modes; j++) {
2027  const Mode *mode = rofi_get_mode(j);
2028  state->modes[j] = textbox_create(
2029  WIDGET(state->sidebar_bar), WIDGET_TYPE_MODE_SWITCHER, "button",
2030  TB_AUTOHEIGHT, (mode == state->sw) ? HIGHLIGHT : NORMAL,
2031  mode_get_display_name(mode), 0.5, 0.5);
2032  box_add(state->sidebar_bar, WIDGET(state->modes[j]), TRUE);
2035  }
2036  } else if (g_ascii_strcasecmp(name, "overlay") == 0) {
2037  state->overlay = textbox_create(
2038  WIDGET(parent_widget), WIDGET_TYPE_TEXTBOX_TEXT, "overlay",
2039  TB_AUTOWIDTH | TB_AUTOHEIGHT, URGENT, "blaat", 0.5, 0);
2040  box_add((box *)parent_widget, WIDGET(state->overlay), FALSE);
2041  widget_disable(WIDGET(state->overlay));
2042  } else if (g_ascii_strncasecmp(name, "textbox", 7) == 0) {
2043  textbox *t = textbox_create(parent_widget, WIDGET_TYPE_TEXTBOX_TEXT, name,
2044  TB_AUTOHEIGHT | TB_WRAP, NORMAL, "", 0, 0);
2045  box_add((box *)parent_widget, WIDGET(t), TRUE);
2046  } else if (g_ascii_strncasecmp(name, "button", 6) == 0) {
2047  textbox *t = textbox_create(parent_widget, WIDGET_TYPE_EDITBOX, name,
2048  TB_AUTOHEIGHT | TB_WRAP, NORMAL, "", 0, 0);
2049  box_add((box *)parent_widget, WIDGET(t), TRUE);
2051  state);
2052  } else if (g_ascii_strncasecmp(name, "icon", 4) == 0) {
2053  icon *t = icon_create(parent_widget, name);
2054  /* small hack to make it clickable */
2055  const char *type = rofi_theme_get_string(WIDGET(t), "action", NULL);
2056  if (type) {
2057  WIDGET(t)->type = WIDGET_TYPE_EDITBOX;
2058  }
2059  box_add((box *)parent_widget, WIDGET(t), TRUE);
2061  state);
2062  } else {
2063  wid = (widget *)box_create(parent_widget, name, ROFI_ORIENTATION_VERTICAL);
2064  box_add((box *)parent_widget, WIDGET(wid), TRUE);
2065  // g_error("The widget %s does not exists. Invalid layout.", name);
2066  }
2067  if (wid) {
2068  GList *list = rofi_theme_get_list_strings(wid, "children");
2069  if (list == NULL) {
2070  if (defaults) {
2071  char **a = g_strsplit(defaults, ",", 0);
2072  for (int i = 0; a && a[i]; i++) {
2073  rofi_view_add_widget(state, wid, a[i]);
2074  }
2075  g_strfreev(a);
2076  }
2077  } else {
2078  for (const GList *iter = g_list_first(list); iter != NULL;
2079  iter = g_list_next(iter)) {
2080  rofi_view_add_widget(state, wid, (const char *)iter->data);
2081  }
2082  g_list_free_full(list, g_free);
2083  }
2084  }
2085 }
2086 
2088  xcb_query_pointer_cookie_t pointer_cookie =
2089  xcb_query_pointer(xcb->connection, CacheState.main_window);
2090  xcb_query_pointer_reply_t *pointer_reply =
2091  xcb_query_pointer_reply(xcb->connection, pointer_cookie, NULL);
2092 
2093  if (pointer_reply == NULL) {
2094  return;
2095  }
2096 
2097  rofi_view_handle_mouse_motion(state, pointer_reply->win_x,
2098  pointer_reply->win_y, config.hover_select);
2099 
2100  free(pointer_reply);
2101 }
2102 
2103 RofiViewState *rofi_view_create(Mode *sw, const char *input,
2104  MenuFlags menu_flags,
2105  void (*finalize)(RofiViewState *)) {
2106  TICK();
2108  state->menu_flags = menu_flags;
2109  state->sw = sw;
2110  state->selected_line = UINT32_MAX;
2111  state->retv = MENU_CANCEL;
2112  state->distance = NULL;
2113  state->quit = FALSE;
2114  state->skip_absorb = FALSE;
2115  // We want to filter on the first run.
2116  state->refilter = TRUE;
2117  state->finalize = finalize;
2118  state->mouse_seen = FALSE;
2119 
2120  // Request the lines to show.
2121  state->num_lines = mode_get_num_entries(sw);
2122 
2123  if (state->sw) {
2124  char *title =
2125  g_strdup_printf("rofi - %s", mode_get_display_name(state->sw));
2127  g_free(title);
2128  } else {
2130  }
2131  TICK_N("Startup notification");
2132 
2133  // Get active monitor size.
2134  TICK_N("Get active monitor");
2135 
2136  state->main_window = box_create(NULL, "window", ROFI_ORIENTATION_VERTICAL);
2137  // Get children.
2138  GList *list =
2139  rofi_theme_get_list_strings(WIDGET(state->main_window), "children");
2140  if (list == NULL) {
2141  rofi_view_add_widget(state, WIDGET(state->main_window), "mainbox");
2142  } else {
2143  for (const GList *iter = list; iter != NULL; iter = g_list_next(iter)) {
2144  rofi_view_add_widget(state, WIDGET(state->main_window),
2145  (const char *)iter->data);
2146  }
2147  g_list_free_full(list, g_free);
2148  }
2149 
2150  if (state->text && input) {
2151  textbox_text(state->text, input);
2152  textbox_cursor_end(state->text);
2153  }
2154 
2155  // filtered list
2156  state->line_map = g_malloc0_n(state->num_lines, sizeof(unsigned int));
2157  state->distance = (int *)g_malloc0_n(state->num_lines, sizeof(int));
2158 
2160  // Only needed when window is fixed size.
2163  }
2164 
2165  state->height = rofi_view_calculate_height(state);
2166  // Move the window to the correct x,y position.
2169 
2170  state->quit = FALSE;
2171  rofi_view_refilter(state);
2172  rofi_view_update(state, TRUE);
2173  xcb_map_window(xcb->connection, CacheState.main_window);
2175  rofi_view_ping_mouse(state);
2176  xcb_flush(xcb->connection);
2177 
2179  /* When Override Redirect, the WM will not let us know we can take focus, so
2180  * just steal it */
2181  if (((menu_flags & MENU_NORMAL_WINDOW) == 0)) {
2182  rofi_xcb_set_input_focus(CacheState.main_window);
2183  }
2184 
2185  if (xcb->sncontext != NULL) {
2186  sn_launchee_context_complete(xcb->sncontext);
2187  }
2188  return state;
2189 }
2190 
2191 int rofi_view_error_dialog(const char *msg, int markup) {
2193  state->retv = MENU_CANCEL;
2194  state->menu_flags = MENU_ERROR_DIALOG;
2195  state->finalize = process_result;
2196 
2197  state->main_window = box_create(NULL, "window", ROFI_ORIENTATION_VERTICAL);
2198  box *box = box_create(WIDGET(state->main_window), "error-message",
2200  box_add(state->main_window, WIDGET(box), TRUE);
2201  state->text =
2203  (TB_AUTOHEIGHT | TB_WRAP) + ((markup) ? TB_MARKUP : 0),
2204  NORMAL, (msg != NULL) ? msg : "", 0, 0);
2205  box_add(box, WIDGET(state->text), TRUE);
2206 
2207  // Make sure we enable fixed num lines when in normal window mode.
2210  }
2212  state->height = rofi_view_calculate_height(state);
2213 
2214  // Calculate window position.
2216 
2217  // Move the window to the correct x,y position.
2219 
2220  // Display it.
2221  xcb_map_window(xcb->connection, CacheState.main_window);
2223 
2224  if (xcb->sncontext != NULL) {
2225  sn_launchee_context_complete(xcb->sncontext);
2226  }
2227 
2228  // Set it as current window.
2229  rofi_view_set_active(state);
2230  return TRUE;
2231 }
2232 
2233 void rofi_view_hide(void) {
2234  if (CacheState.main_window != XCB_WINDOW_NONE) {
2236  xcb_unmap_window(xcb->connection, CacheState.main_window);
2238  }
2239 }
2240 
2242  g_debug("Cleanup.");
2243  if (CacheState.idle_timeout > 0) {
2244  g_source_remove(CacheState.idle_timeout);
2245  CacheState.idle_timeout = 0;
2246  }
2247  if (CacheState.refilter_timeout > 0) {
2248  g_source_remove(CacheState.refilter_timeout);
2249  CacheState.refilter_timeout = 0;
2250  }
2251  if (CacheState.user_timeout > 0) {
2252  g_source_remove(CacheState.user_timeout);
2253  CacheState.user_timeout = 0;
2254  }
2255  if (CacheState.repaint_source > 0) {
2256  g_source_remove(CacheState.repaint_source);
2257  CacheState.repaint_source = 0;
2258  }
2259  if (CacheState.fake_bg) {
2260  cairo_surface_destroy(CacheState.fake_bg);
2261  CacheState.fake_bg = NULL;
2262  }
2263  if (CacheState.edit_draw) {
2264  cairo_destroy(CacheState.edit_draw);
2265  CacheState.edit_draw = NULL;
2266  }
2267  if (CacheState.edit_surf) {
2268  cairo_surface_destroy(CacheState.edit_surf);
2269  CacheState.edit_surf = NULL;
2270  }
2271  if (CacheState.main_window != XCB_WINDOW_NONE) {
2272  g_debug("Unmapping and free'ing window");
2273  xcb_unmap_window(xcb->connection, CacheState.main_window);
2275  xcb_free_gc(xcb->connection, CacheState.gc);
2276  xcb_free_pixmap(xcb->connection, CacheState.edit_pixmap);
2277  xcb_destroy_window(xcb->connection, CacheState.main_window);
2278  CacheState.main_window = XCB_WINDOW_NONE;
2279  }
2280  if (map != XCB_COLORMAP_NONE) {
2281  xcb_free_colormap(xcb->connection, map);
2282  map = XCB_COLORMAP_NONE;
2283  }
2284  xcb_flush(xcb->connection);
2285  g_assert(g_queue_is_empty(&(CacheState.views)));
2286 }
2288  TICK_N("Setup Threadpool, start");
2289  if (config.threads == 0) {
2290  config.threads = 1;
2291  long procs = sysconf(_SC_NPROCESSORS_CONF);
2292  if (procs > 0) {
2293  config.threads = MIN(procs, 128l);
2294  }
2295  }
2296  // Create thread pool
2297  GError *error = NULL;
2298  tpool = g_thread_pool_new(rofi_view_call_thread, NULL, config.threads, FALSE,
2299  &error);
2300  if (error == NULL) {
2301  // Idle threads should stick around for a max of 60 seconds.
2302  g_thread_pool_set_max_idle_time(60000);
2303  // We are allowed to have
2304  g_thread_pool_set_max_threads(tpool, config.threads, &error);
2305  }
2306  // If error occurred during setup of pool, tell user and exit.
2307  if (error != NULL) {
2308  g_warning("Failed to setup thread pool: '%s'", error->message);
2309  g_error_free(error);
2310  exit(EXIT_FAILURE);
2311  }
2312  TICK_N("Setup Threadpool, done");
2313 }
2315  if (tpool) {
2316  g_thread_pool_free(tpool, TRUE, TRUE);
2317  tpool = NULL;
2318  }
2319 }
2320 Mode *rofi_view_get_mode(RofiViewState *state) { return state->sw; }
2321 
2322 void rofi_view_set_overlay(RofiViewState *state, const char *text) {
2323  if (state->overlay == NULL || state->list_view == NULL) {
2324  return;
2325  }
2326  if (text == NULL) {
2327  widget_disable(WIDGET(state->overlay));
2328  return;
2329  }
2330  widget_enable(WIDGET(state->overlay));
2331  textbox_text(state->overlay, text);
2332  // We want to queue a repaint.
2334 }
2335 
2337  if (state->text) {
2338  textbox_text(state->text, "");
2339  rofi_view_set_selected_line(state, 0);
2340  }
2341 }
2342 
2345 }
2346 
2348  state->sw = mode;
2349  // Update prompt;
2350  if (state->prompt) {
2351  rofi_view_update_prompt(state);
2352  }
2353  if (state->sw) {
2354  char *title =
2355  g_strdup_printf("rofi - %s", mode_get_display_name(state->sw));
2357  g_free(title);
2358  } else {
2360  }
2361  if (state->sidebar_bar) {
2362  for (unsigned int j = 0; j < state->num_modes; j++) {
2363  const Mode *tb_mode = rofi_get_mode(j);
2364  textbox_font(state->modes[j],
2365  (tb_mode == state->sw) ? HIGHLIGHT : NORMAL);
2366  }
2367  }
2368  rofi_view_restart(state);
2369  state->reload = TRUE;
2370  state->refilter = TRUE;
2371  rofi_view_refilter(state);
2372  rofi_view_update(state, TRUE);
2373 }
2374 
2375 xcb_window_t rofi_view_get_window(void) { return CacheState.main_window; }
2376 
2377 void rofi_view_set_window_title(const char *title) {
2378  ssize_t len = strlen(title);
2379  xcb_change_property(xcb->connection, XCB_PROP_MODE_REPLACE,
2380  CacheState.main_window, xcb->ewmh._NET_WM_NAME,
2381  xcb->ewmh.UTF8_STRING, 8, len, title);
2382  xcb_change_property(xcb->connection, XCB_PROP_MODE_REPLACE,
2383  CacheState.main_window, XCB_ATOM_WM_NAME, XCB_ATOM_STRING,
2384  8, len, title);
2385 }
@ WL_SOUTH_EAST
Definition: rofi-types.h:251
@ WL_CENTER
Definition: rofi-types.h:237
@ WL_NORTH_WEST
Definition: rofi-types.h:247
@ WL_SOUTH
Definition: rofi-types.h:243
@ WL_NORTH_EAST
Definition: rofi-types.h:249
@ WL_WEST
Definition: rofi-types.h:245
@ WL_NORTH
Definition: rofi-types.h:239
@ WL_EAST
Definition: rofi-types.h:241
@ WL_SOUTH_WEST
Definition: rofi-types.h:253
PangoAttrList * helper_token_match_get_pango_attr(RofiHighlightColorStyle th, rofi_int_matcher **tokens, const char *input, PangoAttrList *retv)
Definition: helper.c:487
gboolean helper_validate_font(PangoFontDescription *pfd, const char *font)
Definition: helper.c:628
void helper_tokenize_free(rofi_int_matcher **tokens)
Definition: helper.c:119
unsigned int levenshtein(const char *needle, const glong needlelen, const char *haystack, const glong haystacklen)
Definition: helper.c:772
int rofi_scorer_fuzzy_evaluate(const char *pattern, glong plen, const char *str, glong slen)
Definition: helper.c:920
char * rofi_expand_path(const char *input)
Definition: helper.c:740
rofi_int_matcher ** helper_tokenize(const char *input, int case_sensitive)
Definition: helper.c:263
guint key_binding_get_action_from_name(const char *name)
Definition: keyb.c:396
BindingsScope
Definition: keyb.h:43
KeyBindingAction
Definition: keyb.h:58
MouseBindingMouseDefaultAction
Definition: keyb.h:168
@ SCOPE_MOUSE_LISTVIEW_ELEMENT
Definition: keyb.h:46
@ SCOPE_MOUSE_EDITBOX
Definition: keyb.h:49
@ SCOPE_MOUSE_LISTVIEW
Definition: keyb.h:45
@ SCOPE_MOUSE_SCROLLBAR
Definition: keyb.h:50
@ SCOPE_GLOBAL
Definition: keyb.h:44
@ SCOPE_MOUSE_MODE_SWITCHER
Definition: keyb.h:51
@ ROW_LAST
Definition: keyb.h:109
@ CUSTOM_4
Definition: keyb.h:115
@ CUSTOM_17
Definition: keyb.h:128
@ CUSTOM_12
Definition: keyb.h:123
@ CUSTOM_9
Definition: keyb.h:120
@ REMOVE_TO_SOL
Definition: keyb.h:88
@ ROW_RIGHT
Definition: keyb.h:100
@ ROW_UP
Definition: keyb.h:101
@ CUSTOM_8
Definition: keyb.h:119
@ SELECT_ELEMENT_9
Definition: keyb.h:142
@ MOVE_FRONT
Definition: keyb.h:66
@ REMOVE_WORD_FORWARD
Definition: keyb.h:80
@ CHANGE_ELLIPSIZE
Definition: keyb.h:132
@ ACCEPT_CUSTOM_ALT
Definition: keyb.h:93
@ REMOVE_WORD_BACK
Definition: keyb.h:78
@ TOGGLE_SORT
Definition: keyb.h:133
@ ACCEPT_ENTRY
Definition: keyb.h:90
@ ROW_TAB
Definition: keyb.h:103
@ PAGE_NEXT
Definition: keyb.h:107
@ TOGGLE_CASE_SENSITIVITY
Definition: keyb.h:97
@ ELEMENT_NEXT
Definition: keyb.h:104
@ MOVE_CHAR_FORWARD
Definition: keyb.h:76
@ MOVE_WORD_FORWARD
Definition: keyb.h:72
@ MODE_COMPLETE
Definition: keyb.h:95
@ CUSTOM_1
Definition: keyb.h:112
@ SELECT_ELEMENT_6
Definition: keyb.h:139
@ CUSTOM_18
Definition: keyb.h:129
@ CUSTOM_15
Definition: keyb.h:126
@ CUSTOM_11
Definition: keyb.h:122
@ ACCEPT_CUSTOM
Definition: keyb.h:92
@ CUSTOM_5
Definition: keyb.h:116
@ CUSTOM_19
Definition: keyb.h:130
@ REMOVE_TO_EOL
Definition: keyb.h:86
@ SELECT_ELEMENT_3
Definition: keyb.h:136
@ ROW_SELECT
Definition: keyb.h:110
@ PASTE_PRIMARY
Definition: keyb.h:60
@ ROW_DOWN
Definition: keyb.h:102
@ CUSTOM_13
Definition: keyb.h:124
@ PASTE_SECONDARY
Definition: keyb.h:62
@ SELECT_ELEMENT_10
Definition: keyb.h:143
@ PAGE_PREV
Definition: keyb.h:106
@ CUSTOM_3
Definition: keyb.h:114
@ CUSTOM_7
Definition: keyb.h:118
@ SELECT_ELEMENT_5
Definition: keyb.h:138
@ ROW_FIRST
Definition: keyb.h:108
@ CUSTOM_6
Definition: keyb.h:117
@ ROW_LEFT
Definition: keyb.h:99
@ CUSTOM_14
Definition: keyb.h:125
@ SELECT_ELEMENT_4
Definition: keyb.h:137
@ MOVE_WORD_BACK
Definition: keyb.h:70
@ MOVE_END
Definition: keyb.h:68
@ CUSTOM_10
Definition: keyb.h:121
@ MODE_NEXT
Definition: keyb.h:94
@ REMOVE_CHAR_BACK
Definition: keyb.h:84
@ DELETE_ENTRY
Definition: keyb.h:98
@ SELECT_ELEMENT_1
Definition: keyb.h:134
@ CLEAR_LINE
Definition: keyb.h:64
@ CUSTOM_2
Definition: keyb.h:113
@ SELECT_ELEMENT_2
Definition: keyb.h:135
@ SCREENSHOT
Definition: keyb.h:131
@ CANCEL
Definition: keyb.h:111
@ ELEMENT_PREV
Definition: keyb.h:105
@ MODE_PREVIOUS
Definition: keyb.h:96
@ ACCEPT_ALT
Definition: keyb.h:91
@ SELECT_ELEMENT_7
Definition: keyb.h:140
@ MOVE_CHAR_BACK
Definition: keyb.h:74
@ SELECT_ELEMENT_8
Definition: keyb.h:141
@ REMOVE_CHAR_FORWARD
Definition: keyb.h:82
@ CUSTOM_16
Definition: keyb.h:127
@ MOUSE_CLICK_DOWN
Definition: keyb.h:169
@ MOUSE_DCLICK_UP
Definition: keyb.h:172
@ MOUSE_CLICK_UP
Definition: keyb.h:170
@ MOUSE_DCLICK_DOWN
Definition: keyb.h:171
char * mode_get_completion(const Mode *mode, unsigned int selected_line)
Definition: mode.c:109
unsigned int mode_get_num_entries(const Mode *mode)
Definition: mode.c:58
const char * mode_get_display_name(const Mode *mode)
Definition: mode.c:172
char * mode_get_display_value(const Mode *mode, unsigned int selected_line, int *state, GList **attribute_list, int get_entry)
Definition: mode.c:64
char * mode_preprocess_input(Mode *mode, const char *input)
Definition: mode.c:195
MenuReturn
Definition: mode.h:65
cairo_surface_t * mode_get_icon(Mode *mode, unsigned int selected_line, unsigned int height)
Definition: mode.c:75
int mode_token_match(const Mode *mode, rofi_int_matcher **tokens, unsigned int selected_line)
Definition: mode.c:138
char * mode_get_message(const Mode *mode)
Definition: mode.c:201
@ MENU_CUSTOM_COMMAND
Definition: mode.h:79
@ MENU_COMPLETE
Definition: mode.h:83
@ MENU_LOWER_MASK
Definition: mode.h:87
@ MENU_PREVIOUS
Definition: mode.h:81
@ MENU_CANCEL
Definition: mode.h:69
@ MENU_QUICK_SWITCH
Definition: mode.h:77
@ MENU_ENTRY_DELETE
Definition: mode.h:75
@ MENU_NEXT
Definition: mode.h:71
@ MENU_CUSTOM_ACTION
Definition: mode.h:85
@ MENU_OK
Definition: mode.h:67
@ MENU_CUSTOM_INPUT
Definition: mode.h:73
void rofi_quit_main_loop(void)
Definition: rofi.c:691
#define color_reset
Definition: rofi.h:107
unsigned int rofi_get_num_enabled_modes(void)
Definition: rofi.c:147
const Mode * rofi_get_mode(unsigned int index)
Definition: rofi.c:149
#define color_green
Definition: rofi.h:113
#define TICK()
Definition: timings.h:64
#define TICK_N(a)
Definition: timings.h:69
void textbox_font(textbox *tb, TextBoxFontType tbft)
Definition: textbox.c:277
TextboxFlags
Definition: textbox.h:89
int textbox_keybinding(textbox *tb, KeyBindingAction action)
Definition: textbox.c:771
TextBoxFontType
Definition: textbox.h:100
void textbox_set_pango_attributes(textbox *tb, PangoAttrList *list)
Definition: textbox.c:350
const char * textbox_get_visible_text(const textbox *tb)
Definition: textbox.c:338
PangoAttrList * textbox_get_pango_attributes(textbox *tb)
Definition: textbox.c:344
textbox * textbox_create(widget *parent, WidgetType type, const char *name, TextboxFlags flags, TextBoxFontType tbft, const char *text, double xalign, double yalign)
Definition: textbox.c:186
void textbox_set_pango_context(const char *font, PangoContext *p)
Definition: textbox.c:871
void textbox_cursor_end(textbox *tb)
Definition: textbox.c:645
gboolean textbox_append_text(textbox *tb, const char *pad, const int pad_len)
Definition: textbox.c:833
void textbox_text(textbox *tb, const char *text)
Definition: textbox.c:358
@ TB_AUTOHEIGHT
Definition: textbox.h:90
@ TB_PASSWORD
Definition: textbox.h:95
@ TB_MARKUP
Definition: textbox.h:93
@ TB_WRAP
Definition: textbox.h:94
@ TB_EDITABLE
Definition: textbox.h:92
@ TB_AUTOWIDTH
Definition: textbox.h:91
@ URGENT
Definition: textbox.h:104
@ HIGHLIGHT
Definition: textbox.h:115
@ NORMAL
Definition: textbox.h:102
void rofi_view_cleanup()
Definition: view.c:2241
void rofi_view_set_overlay(RofiViewState *state, const char *text)
Definition: view.c:2322
void __create_window(MenuFlags menu_flags)
Definition: view.c:782
void rofi_view_clear_input(RofiViewState *state)
Definition: view.c:2336
void rofi_view_switch_mode(RofiViewState *state, Mode *mode)
Definition: view.c:2347
void rofi_view_hide(void)
Definition: view.c:2233
void rofi_view_reload(void)
Definition: view.c:528
Mode * rofi_view_get_mode(RofiViewState *state)
Definition: view.c:2320
xcb_window_t rofi_view_get_window(void)
Definition: view.c:2375
void rofi_view_remove_active(RofiViewState *state)
Definition: view.c:551
RofiViewState * rofi_view_get_active(void)
Definition: view.c:549
int rofi_view_error_dialog(const char *msg, int markup)
Definition: view.c:2191
void rofi_view_set_active(RofiViewState *state)
Definition: view.c:558
void rofi_view_queue_redraw(void)
Definition: view.c:535
void rofi_view_restart(RofiViewState *state)
Definition: view.c:544
MenuFlags
Definition: view.h:48
void rofi_view_handle_text(RofiViewState *state, char *text)
Definition: view.c:1643
void rofi_view_trigger_action(RofiViewState *state, BindingsScope scope, guint action)
Definition: view.c:1607
MenuReturn rofi_view_get_return_value(const RofiViewState *state)
Definition: view.c:617
unsigned int rofi_view_get_completed(const RofiViewState *state)
Definition: view.c:634
gboolean rofi_view_check_action(RofiViewState *state, BindingsScope scope, guint action)
Definition: view.c:1576
void rofi_view_handle_mouse_motion(RofiViewState *state, gint x, gint y, gboolean find_mouse_target)
Definition: view.c:1685
void rofi_view_temp_click_to_exit(RofiViewState *state, xcb_window_t target)
Definition: view.c:1774
void rofi_view_finalize(RofiViewState *state)
Definition: view.c:1323
void rofi_view_set_selected_line(RofiViewState *state, unsigned int selected_line)
Definition: view.c:581
void rofi_view_temp_configure_notify(RofiViewState *state, xcb_configure_notify_event_t *xce)
Definition: view.c:1740
RofiViewState * rofi_view_create(Mode *sw, const char *input, MenuFlags menu_flags, void(*finalize)(RofiViewState *))
Definition: view.c:2103
void rofi_view_frame_callback(void)
Definition: view.c:1783
void rofi_view_free(RofiViewState *state)
Definition: view.c:599
const char * rofi_view_get_user_input(const RofiViewState *state)
Definition: view.c:638
unsigned int rofi_view_get_selected_line(const RofiViewState *state)
Definition: view.c:621
unsigned int rofi_view_get_next_position(const RofiViewState *state)
Definition: view.c:625
void rofi_view_maybe_update(RofiViewState *state)
Definition: view.c:1713
@ MENU_PASSWORD
Definition: view.h:52
@ MENU_NORMAL_WINDOW
Definition: view.h:54
@ MENU_ERROR_DIALOG
Definition: view.h:56
@ MENU_NORMAL
Definition: view.h:50
void rofi_view_ellipsize_start(RofiViewState *state)
Definition: view.c:2343
void rofi_capture_screenshot(void)
Definition: view.c:179
void rofi_view_workers_initialize(void)
Definition: view.c:2287
void rofi_view_set_window_title(const char *title)
Definition: view.c:2377
void rofi_view_get_current_monitor(int *width, int *height)
Definition: view.c:144
void rofi_view_workers_finalize(void)
Definition: view.c:2314
void box_add(box *box, widget *child, gboolean expand)
Definition: box.c:286
box * box_create(widget *parent, const char *name, RofiOrientation type)
Definition: box.c:346
container * container_create(widget *parent, const char *name)
Definition: container.c:102
void container_add(container *container, widget *child)
Definition: container.c:67
void icon_set_surface(icon *icon, cairo_surface_t *surf)
Definition: icon.c:140
icon * icon_create(widget *parent, const char *name)
Definition: icon.c:153
void listview_nav_page_next(listview *lv)
Definition: listview.c:989
void listview_set_fixed_num_lines(listview *lv)
Definition: listview.c:1073
void listview_set_num_lines(listview *lv, unsigned int num_lines)
Definition: listview.c:1055
void listview_set_num_elements(listview *lv, unsigned int rows)
Definition: listview.c:561
listview * listview_create(widget *parent, const char *name, listview_update_callback cb, void *udata, unsigned int eh, gboolean reverse)
Definition: listview.c:711
void listview_nav_right(listview *lv)
Definition: listview.c:897
void listview_set_mouse_activated_cb(listview *lv, listview_mouse_activated_cb cb, void *udata)
Definition: listview.c:1047
void listview_toggle_ellipsizing(listview *lv)
Definition: listview.c:1088
void listview_set_selected(listview *lv, unsigned int selected)
Definition: listview.c:585
void listview_set_max_lines(listview *lv, unsigned int max_lines)
Definition: listview.c:1061
void listview_nav_left(listview *lv)
Definition: listview.c:876
void listview_set_scroll_type(listview *lv, ScrollType type)
Definition: listview.c:1041
void listview_set_ellipsize_start(listview *lv)
Definition: listview.c:1079
void listview_nav_prev(listview *lv)
Definition: listview.c:817
unsigned int listview_get_selected(listview *lv)
Definition: listview.c:578
void listview_set_filtered(listview *lv, gboolean filtered)
Definition: listview.c:1105
void listview_nav_up(listview *lv)
Definition: listview.c:839
void listview_nav_next(listview *lv)
Definition: listview.c:811
void listview_nav_page_prev(listview *lv)
Definition: listview.c:979
void listview_set_selection_changed_callback(listview *lv, listview_selection_changed_callback cb, void *udata)
Definition: listview.c:1111
void listview_nav_down(listview *lv)
Definition: listview.c:857
WidgetTriggerActionResult widget_trigger_action(widget *wid, guint action, gint x, gint y)
Definition: widget.c:546
void widget_queue_redraw(widget *wid)
Definition: widget.c:487
void widget_free(widget *wid)
Definition: widget.c:425
static void widget_disable(widget *widget)
Definition: widget.h:170
void widget_resize(widget *widget, short w, short h)
Definition: widget.c:87
WidgetType
Definition: widget.h:56
static void widget_enable(widget *widget)
Definition: widget.h:178
void widget_draw(widget *widget, cairo_t *d)
Definition: widget.c:135
void widget_xy_to_relative(widget *widget, gint *x, gint *y)
Definition: widget.c:468
#define WIDGET(a)
Definition: widget.h:119
WidgetTriggerActionResult
Definition: widget.h:76
widget * widget_find_mouse_target(widget *wid, WidgetType type, gint x, gint y)
Definition: widget.c:510
void widget_set_trigger_action_handler(widget *wid, widget_trigger_action_cb cb, void *cb_data)
Definition: widget.c:557
int widget_get_desired_height(widget *wid, const int width)
Definition: widget.c:644
gboolean widget_motion_notify(widget *wid, gint x, gint y)
Definition: widget.c:566
gboolean widget_need_redraw(widget *wid)
Definition: widget.c:500
@ WIDGET_TYPE_UNKNOWN
Definition: widget.h:58
@ WIDGET_TYPE_LISTVIEW_ELEMENT
Definition: widget.h:62
@ WIDGET_TYPE_TEXTBOX_TEXT
Definition: widget.h:70
@ WIDGET_TYPE_MODE_SWITCHER
Definition: widget.h:68
@ WIDGET_TYPE_EDITBOX
Definition: widget.h:64
@ WIDGET_TRIGGER_ACTION_RESULT_HANDLED
Definition: widget.h:80
@ WIDGET_TRIGGER_ACTION_RESULT_GRAB_MOTION_END
Definition: widget.h:84
@ WIDGET_TRIGGER_ACTION_RESULT_GRAB_MOTION_BEGIN
Definition: widget.h:82
@ WIDGET_TRIGGER_ACTION_RESULT_IGNORED
Definition: widget.h:78
@ P_INTEGER
Definition: rofi-types.h:12
@ P_STRING
Definition: rofi-types.h:16
@ ROFI_ORIENTATION_HORIZONTAL
Definition: rofi-types.h:143
@ ROFI_ORIENTATION_VERTICAL
Definition: rofi-types.h:142
RofiCursorType
Definition: rofi-types.h:149
@ ROFI_CURSOR_POINTER
Definition: rofi-types.h:151
@ ROFI_CURSOR_TEXT
Definition: rofi-types.h:152
@ ROFI_CURSOR_DEFAULT
Definition: rofi-types.h:150
@ ROFI_HL_UNDERLINE
Definition: rofi-types.h:58
@ ROFI_HL_BOLD
Definition: rofi-types.h:56
Settings config
#define DEFAULT_MENU_LINES
Definition: settings.h:190
#define DEFAULT_MENU_WIDTH
Definition: settings.h:194
@ SORT_FZF
Definition: settings.h:49
@ SORT_NORMAL
Definition: settings.h:49
PropertyValue value
Definition: rofi-types.h:297
PropertyType type
Definition: rofi-types.h:295
unsigned int filtered_lines
Definition: view-internal.h:80
container * mesg_box
Definition: view-internal.h:68
textbox * text
Definition: view-internal.h:59
widget * motion_target
textbox * mesg_tb
Definition: view-internal.h:70
textbox * overlay
Definition: view-internal.h:66
struct RofiViewState::@7 mouse
icon * icon_current_entry
textbox ** modes
listview * list_view
Definition: view-internal.h:64
unsigned int num_lines
Definition: view-internal.h:77
unsigned int num_modes
MenuReturn retv
Definition: view-internal.h:94
void(* finalize)(struct RofiViewState *state)
textbox * prompt
Definition: view-internal.h:57
unsigned int * line_map
Definition: view-internal.h:75
textbox * tb_filtered_rows
rofi_int_matcher ** tokens
textbox * tb_current_entry
textbox * tb_total_rows
unsigned int selected_line
Definition: view-internal.h:92
KeyBindingAction prev_action
Definition: view-internal.h:83
textbox * case_indicator
Definition: view-internal.h:61
MenuFlags menu_flags
WindowLocation location
Definition: settings.h:84
unsigned int threads
Definition: settings.h:143
int x_offset
Definition: settings.h:88
unsigned int scroll_method
Definition: settings.h:144
int y_offset
Definition: settings.h:86
unsigned int auto_select
Definition: settings.h:126
unsigned int case_sensitive
Definition: settings.h:114
unsigned int sort
Definition: settings.h:96
char * menu_font
Definition: settings.h:59
unsigned int sidebar_mode
Definition: settings.h:120
gboolean benchmark_ui
Definition: settings.h:173
int dpi
Definition: settings.h:141
unsigned int refilter_timeout_limit
Definition: settings.h:183
SortingMethod sorting_method_enum
Definition: settings.h:98
gboolean hover_select
Definition: settings.h:122
int element_height
Definition: settings.h:118
Definition: box.c:40
Definition: icon.c:39
const char * pattern
Definition: view.c:678
unsigned int count
Definition: view.c:675
GMutex * mutex
Definition: view.c:664
unsigned int stop
Definition: view.c:673
thread_state st
Definition: view.c:659
RofiViewState * state
Definition: view.c:669
unsigned int * acount
Definition: view.c:666
unsigned int start
Definition: view.c:671
GCond * cond
Definition: view.c:662
void(* callback)(struct _thread_state *t, gpointer data)
Definition: rofi-types.h:321
RofiCursorType cursor_type
Definition: xcb.h:94
xcb_connection_t * connection
Definition: xcb-internal.h:47
SnLauncheeContext * sncontext
Definition: xcb-internal.h:52
xcb_ewmh_connection_t ewmh
Definition: xcb-internal.h:48
xcb_screen_t * screen
Definition: xcb-internal.h:49
char * text
Definition: textbox.h:65
GList * rofi_theme_get_list_strings(const widget *widget, const char *property)
Definition: theme.c:1267
RofiDistance rofi_theme_get_distance(const widget *widget, const char *property, int def)
Definition: theme.c:877
ThemeWidget * rofi_config_find_widget(const char *name, const char *state, gboolean exact)
Definition: theme.c:778
int rofi_theme_get_boolean(const widget *widget, const char *property, int def)
Definition: theme.c:903
int distance_get_pixel(RofiDistance d, RofiOrientation ori)
Definition: theme.c:1415
Property * rofi_theme_find_property(ThemeWidget *widget, PropertyType type, const char *property, gboolean exact)
Definition: theme.c:740
RofiHighlightColorStyle rofi_theme_get_highlight(widget *widget, const char *property, RofiHighlightColorStyle th)
Definition: theme.c:1320
int rofi_theme_get_integer(const widget *widget, const char *property, int def)
Definition: theme.c:840
int rofi_theme_get_position(const widget *widget, const char *property, int def)
Definition: theme.c:815
const char * rofi_theme_get_string(const widget *widget, const char *property, const char *def)
Definition: theme.c:990
static void rofi_view_call_thread(gpointer data, gpointer user_data)
Definition: view.c:688
cairo_surface_t * fake_bg
Definition: view.c:95
static void rofi_view_nav_last(RofiViewState *state)
Definition: view.c:1027
static gboolean rofi_view_repaint(G_GNUC_UNUSED void *data)
Definition: view.c:272
static WidgetTriggerActionResult textbox_button_trigger_action(widget *wid, MouseBindingMouseDefaultAction action, G_GNUC_UNUSED gint x, G_GNUC_UNUSED gint y, G_GNUC_UNUSED void *user_data)
Definition: view.c:1809
static char * get_matching_state(void)
Definition: view.c:152
static void rofi_view_set_user_timeout(G_GNUC_UNUSED gpointer data)
Definition: view.c:508
GList * list_of_warning_msgs
Definition: rofi.c:87
static gboolean rofi_view_reload_idle(G_GNUC_UNUSED gpointer data)
Definition: view.c:469
static gboolean bench_update(void)
Definition: view.c:248
struct _thread_state_view thread_state_view
static RofiViewState * __rofi_view_state_create(void)
Definition: view.c:650
guint idle_timeout
Definition: view.c:113
guint refilter_timeout_count
Definition: view.c:116
static void rofi_view_nav_row_select(RofiViewState *state)
Definition: view.c:997
GQueue views
Definition: view.c:109
static void rofi_view_listview_mouse_activated_cb(listview *lv, gboolean custom, void *udata)
Definition: view.c:1867
static void rofi_view_input_changed()
Definition: view.c:1333
GTimer * time
Definition: view.c:239
cairo_surface_t * edit_surf
Definition: view.c:101
static void rofi_view_add_widget(RofiViewState *state, widget *parent_widget, const char *name)
Definition: view.c:1880
static void update_callback(textbox *t, icon *ico, unsigned int index, void *udata, TextBoxFontType *type, gboolean full)
Definition: view.c:1063
static void rofi_view_nav_row_tab(RofiViewState *state)
Definition: view.c:973
static void rofi_view_setup_fake_transparency(widget *win, const char *const fake_background)
Definition: view.c:729
static struct @2 BenchMark
static void rofi_view_reload_message_bar(RofiViewState *state)
Definition: view.c:432
static void rofi_view_nav_first(RofiViewState *state)
Definition: view.c:1017
gboolean do_bench
Definition: view.c:232
xcb_window_t main_window
Definition: view.c:93
static gboolean rofi_view_refilter_real(RofiViewState *state)
Definition: view.c:1164
xcb_gcontext_t gc
Definition: view.c:97
guint user_timeout
Definition: view.c:118
cairo_t * edit_draw
Definition: view.c:103
void rofi_view_update(RofiViewState *state, gboolean qr)
Definition: view.c:1118
guint refilter_timeout
Definition: view.c:115
static const int loc_transtable[9]
Definition: view.c:311
xcb_pixmap_t edit_pixmap
Definition: view.c:99
static void rofi_view_trigger_global_action(KeyBindingAction action)
Definition: view.c:1335
workarea mon
Definition: view.c:111
int fake_bgrel
Definition: view.c:105
static void filter_elements(thread_state *ts, G_GNUC_UNUSED gpointer user_data)
Definition: view.c:693
void process_result(RofiViewState *state)
Definition: rofi.c:217
static void rofi_view_update_prompt(RofiViewState *state)
Definition: view.c:292
static gboolean rofi_view_user_timeout(G_GNUC_UNUSED gpointer data)
Definition: view.c:502
static void rofi_view_refilter(RofiViewState *state)
Definition: view.c:1292
X11CursorType cursor_type
Definition: view.c:126
static int rofi_view_calculate_height(RofiViewState *state)
Definition: view.c:1792
GThreadPool * tpool
Definition: view.c:83
double min
Definition: view.c:245
RofiViewState * current_active_menu
Definition: view.c:86
MenuFlags flags
Definition: view.c:107
unsigned long long count
Definition: view.c:120
static void rofi_view_calculate_window_position(RofiViewState *state)
Definition: view.c:315
uint64_t draws
Definition: view.c:241
double last_ts
Definition: view.c:243
static void rofi_view_set_cursor(RofiCursorType type)
Definition: view.c:1673
static void rofi_view_take_action(const char *name)
Definition: view.c:486
static void selection_changed_callback(G_GNUC_UNUSED listview *lv, unsigned int index, void *udata)
Definition: view.c:1035
static void rofi_view_ping_mouse(RofiViewState *state)
Definition: view.c:2087
static void rofi_view_window_update_size(RofiViewState *state)
Definition: view.c:402
gboolean fullscreen
Definition: view.c:124
static void rofi_view_calculate_window_width(RofiViewState *state)
Definition: view.c:951
static X11CursorType rofi_cursor_type_to_x11_cursor_type(RofiCursorType type)
Definition: view.c:1650
static RofiCursorType rofi_view_resolve_cursor(RofiViewState *state, gint x, gint y)
Definition: view.c:1665
static int lev_sort(const void *p1, const void *p2, void *arg)
Definition: view.c:168
struct @1 CacheState
static WidgetTriggerActionResult textbox_sidebar_modes_trigger_action(widget *wid, MouseBindingMouseDefaultAction action, G_GNUC_UNUSED gint x, G_GNUC_UNUSED gint y, G_GNUC_UNUSED void *user_data)
Definition: view.c:1838
static void _rofi_view_reload_row(RofiViewState *state)
Definition: view.c:1154
guint repaint_source
Definition: view.c:122
static void rofi_view_refilter_force(RofiViewState *state)
Definition: view.c:1308
WidgetTriggerActionResult widget_check_action(widget *wid, G_GNUC_UNUSED guint action, G_GNUC_UNUSED gint x, G_GNUC_UNUSED gint y)
Definition: widget.c:529
xcb_colormap_t map
Definition: xcb.c:98
int monitor_active(workarea *mon)
Definition: xcb.c:992
void display_early_cleanup(void)
Definition: xcb.c:1749
cairo_surface_t * x11_helper_get_screenshot_surface(void)
Definition: xcb.c:337
xcb_stuff * xcb
Definition: xcb.c:91
xcb_depth_t * depth
Definition: xcb.c:96
void rofi_xcb_revert_input_focus(void)
Definition: xcb.c:1358
void rofi_xcb_set_input_focus(xcb_window_t w)
Definition: xcb.c:1335
void x11_set_cursor(xcb_window_t window, X11CursorType type)
Definition: xcb.c:1806
cairo_surface_t * x11_helper_get_bg_surface(void)
Definition: xcb.c:363
xcb_window_t xcb_stuff_get_root_window(void)
Definition: xcb.c:1747
void window_set_atom_prop(xcb_window_t w, xcb_atom_t prop, xcb_atom_t *atoms, int count)
Definition: xcb.c:403
void cairo_image_surface_blur(cairo_surface_t *surface, double radius, double deviation)
Definition: xcb.c:167
void x11_disable_decoration(xcb_window_t window)
Definition: xcb.c:1782
xcb_atom_t netatoms[NUM_NETATOMS]
Definition: xcb.c:103
xcb_visualtype_t * visual
Definition: xcb.c:97
X11CursorType
Definition: xcb.h:174
@ CURSOR_POINTER
Definition: xcb.h:178
@ CURSOR_DEFAULT
Definition: xcb.h:176
@ CURSOR_TEXT
Definition: xcb.h:180