Introduction
Introduction Statistics Contact Development Disclaimer Help
window.c - ledit - Text editor (WIP)
git clone git://lumidify.org/ledit.git (fast, but not encrypted)
git clone https://lumidify.org/ledit.git (encrypted, but very slow)
git clone git://4kcetb7mo7hj6grozzybxtotsub5bempzo4lirzc3437amof2c2impyd.onion/…
Log
Files
Refs
README
LICENSE
---
window.c (32063B)
---
1 /* FIXME: replace the bottom bar with generic line entry
2 -> most stuff can be copied from ltk, but I want to think about
3 it a bit more because I don't want to have to maintain two copies
4 of the code, so I want to first turn the necessary parts from ltk
5 into a generic library that can be used here without modifying it */
6 /* FIXME: check if xim handling still works with multiple windows */
7 #include <time.h>
8 #include <math.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <stdarg.h>
12
13 #include <X11/Xlib.h>
14 #include <X11/Xatom.h>
15 #include <X11/Xutil.h>
16 #include <X11/cursorfont.h>
17 #include <pango/pangoxft.h>
18 #include <pango/pango-utils.h> /* for PANGO_VERSION_CHECK */
19 #include <X11/extensions/Xdbe.h>
20
21 #include "util.h"
22 #include "memory.h"
23 #include "common.h"
24 #include "txtbuf.h"
25 #include "window.h"
26 #include "macros.h"
27 #include "config.h"
28 #include "assert.h"
29 #include "draw_util.h"
30 #include "configparser.h"
31
32 enum bb_itemtype {
33 BB_STR,
34 BB_MODE,
35 BB_HLMODE,
36 BB_LINE,
37 BB_BYTE,
38 BB_SEP,
39 BB_LANG
40 };
41
42 struct bb_item {
43 PangoLayout *layout;
44 ledit_draw *draw;
45 int w, h;
46 enum bb_itemtype type;
47 union {
48 int i;
49 ledit_mode m;
50 size_t sz;
51 } val;
52 };
53
54 /* FIXME: Everything to do with the bottom bar is extremely hacky */
55 struct bottom_bar {
56 struct bb_item *items;
57 size_t items_num, items_alloc;
58 int w_per_sep; /* pixels used per separator in bottom bar */
59
60 /* message or editable text display */
61 PangoLayout *line;
62 ledit_draw *line_draw;
63 int line_w, line_h;
64 char *line_text;
65 int line_alloc, line_len;
66 int line_cur_pos; /* current position of cursor */
67 int min_pos; /* minimum position cursor can be at */
68 };
69
70 /*
71 * Recalculate the size of the actual text area (which is managed by the…
72 */
73 static void recalc_text_size(ledit_window *window);
74
75 /*
76 * Get the position and height for the scrollbar handle.
77 * 'height_ret' is set to the height (in pixels) of the scrollbar handle.
78 * 'pos_ret' is set to the y position (in pixels) of the top of the scro…
79 */
80 static void get_scroll_pos_height(ledit_window *windown, double *pos, do…
81
82 /*
83 * Set the scroll offset.
84 * 'pos' is the pixel position of the top of the scrollbar handle.
85 * This performs sanity checks and calls the scroll callback if set.
86 */
87 static void set_scroll_pos(ledit_window *window, double pos);
88
89 /* FIXME: maybe just draw to one big draw instead of keeping all these s…
90 static void
91 set_item_text(ledit_window *window, ledit_theme *theme, struct bb_item *…
92 pango_layout_set_text(item->layout, text, -1);
93 pango_layout_get_pixel_size(item->layout, &item->w, &item->h);
94 draw_grow(window, item->draw, item->w, item->h);
95 XftDrawRect(item->draw->xftdraw, &theme->bar_bg, 0, 0, item->w, …
96 pango_xft_render_layout(item->draw->xftdraw, &theme->bar_fg, ite…
97 }
98
99 void
100 window_set_format_args(ledit_window *window, ledit_mode mode, int hl_mod…
101 struct bb_item *items = window->bb->items;
102 char *text;
103 int changed = 0;
104 ledit_theme *theme = config_get_theme();
105 for (size_t i = 0; i < window->bb->items_num; i++) {
106 switch (items[i].type) {
107 case BB_MODE:
108 if (mode == items[i].val.m)
109 continue;
110 switch (mode) {
111 case NORMAL:
112 text = "Normal";
113 break;
114 case VISUAL:
115 text = "Visual";
116 break;
117 case INSERT:
118 text = "Insert";
119 break;
120 default:
121 text = "ledit is buggy";
122 break;
123 }
124 set_item_text(window, theme, &items[i], text);
125 changed = 1;
126 items[i].val.m = mode;
127 break;
128 case BB_HLMODE:
129 if (hl_mode == items[i].val.i)
130 continue;
131 if (hl_mode)
132 text = "HL";
133 else
134 text = "SL";
135 set_item_text(window, theme, &items[i], text);
136 changed = 1;
137 items[i].val.i = hl_mode;
138 break;
139 /* FIXME: avoid allocating new each time */
140 case BB_LINE:
141 if (line == items[i].val.sz)
142 continue;
143 text = print_fmt("%zu", line);
144 set_item_text(window, theme, &items[i], text);
145 free(text);
146 changed = 1;
147 items[i].val.sz = line;
148 break;
149 case BB_BYTE:
150 if (byte == items[i].val.sz)
151 continue;
152 text = print_fmt("%zu", byte);
153 set_item_text(window, theme, &items[i], text);
154 free(text);
155 changed = 1;
156 items[i].val.sz = byte;
157 break;
158 case BB_LANG:
159 if (lang_index == items[i].val.sz)
160 continue;
161 text = config_get_language_string(lang_index);
162 if (!text)
163 text = "(invalid language)";
164 set_item_text(window, theme, &items[i], text);
165 changed = 1;
166 items[i].val.sz = lang_index;
167 break;
168 default:
169 break;
170 }
171 }
172 if (changed) {
173 recalc_text_size(window);
174 window->redraw = 1;
175 }
176 }
177
178 /* FIXME: shouldn't window->bottom_text_shown also be true when message_…
179 /* FIXME: guard against negative width/height */
180 static void
181 recalc_text_size(ledit_window *window) {
182 ledit_theme *theme = config_get_theme();
183 int bar_h = 0;
184 int total_static_w = 0;
185 int num_sep = 0;
186 struct bb_item *items = window->bb->items;
187 for (size_t i = 0; i < window->bb->items_num; i++) {
188 if (items[i].type == BB_SEP) {
189 num_sep++;
190 } else {
191 total_static_w += items[i].w;
192 if (items[i].h > bar_h)
193 bar_h = items[i].h;
194 }
195 }
196 window->bb->w_per_sep = (window->w - total_static_w) / num_sep;
197 if (window->bottom_text_shown || window->message_shown)
198 bar_h = window->bb->line_h;
199 window->text_w = window->w - theme->scrollbar_width;
200 window->text_h = window->h - bar_h;
201 if (window->text_w < 0)
202 window->text_w = 0;
203 if (window->text_h < 0)
204 window->text_h = 0;
205 }
206
207 static void
208 resize_line_text(ledit_window *window, int min_size) {
209 /* FIXME: use size_t everywhere */
210 ledit_assert(min_size >= 0);
211 size_t cap = ideal_array_size(window->bb->line_alloc, min_size);
212 if (cap > INT_MAX)
213 err_overflow();
214 if (cap != (size_t)window->bb->line_alloc) {
215 window->bb->line_alloc = (int)cap;
216 window->bb->line_text = ledit_realloc(window->bb->line_t…
217 }
218 }
219
220 static void
221 redraw_line_text(ledit_window *window) {
222 ledit_theme *theme = config_get_theme();
223 /* FIXME: set_text doesn't really belong here */
224 pango_layout_set_text(window->bb->line, window->bb->line_text, w…
225 pango_layout_get_pixel_size(window->bb->line, &window->bb->line_…
226 draw_grow(window, window->bb->line_draw, window->bb->line_w, win…
227 XftDrawRect(window->bb->line_draw->xftdraw, &theme->bar_bg, 0, 0…
228 pango_xft_render_layout(window->bb->line_draw->xftdraw, &theme->…
229 recalc_text_size(window);
230 window->redraw = 1;
231 }
232
233 /* FIXME: allow lines longer than window width to be displayed properly …
234 void
235 window_insert_bottom_bar_text(ledit_window *window, char *text, int len)…
236 ledit_assert(len >= -1);
237 ledit_assert(window->bb->line_cur_pos <= window->bb->line_len);
238
239 if (len == -1)
240 len = strlen(text);
241 /* \0 not included in len */
242 resize_line_text(window, window->bb->line_len + len + 1);
243 memmove(
244 window->bb->line_text + window->bb->line_cur_pos + len,
245 window->bb->line_text + window->bb->line_cur_pos,
246 window->bb->line_len - window->bb->line_cur_pos
247 );
248 memcpy(window->bb->line_text + window->bb->line_cur_pos, text, l…
249 window->bb->line_len += len;
250 window->bb->line_text[window->bb->line_len] = '\0';
251 redraw_line_text(window);
252 }
253
254 void
255 window_move_bottom_bar_cursor(ledit_window *window, int movement) {
256 ledit_assert(window->bb->line_cur_pos <= window->bb->line_len);
257 int trailing = 0;
258 int new_index = window->bb->line_cur_pos;
259 pango_layout_move_cursor_visually(
260 window->bb->line, TRUE,
261 new_index, trailing, movement,
262 &new_index, &trailing
263 );
264 while (trailing > 0) {
265 trailing--;
266 /* FIXME: move to common/util */
267 new_index++;
268 while (new_index < window->bb->line_len &&
269 (window->bb->line_text[new_index] & 0xC0) == 0x80)
270 new_index++;
271 }
272 if (new_index < window->bb->min_pos)
273 new_index = window->bb->min_pos;
274 if (new_index > window->bb->line_len)
275 new_index = window->bb->line_len;
276 window->bb->line_cur_pos = new_index;
277 window->redraw = 1;
278 }
279
280 void
281 window_set_bottom_bar_min_pos(ledit_window *window, int pos) {
282 window->bb->min_pos = pos;
283 }
284
285 int
286 window_get_bottom_bar_min_pos(ledit_window *window) {
287 return window->bb->min_pos;
288 }
289
290 void
291 window_bottom_bar_cursor_to_beginning(ledit_window *window) {
292 window->bb->line_cur_pos = window->bb->min_pos;
293 window->redraw = 1;
294 }
295
296 void
297 window_bottom_bar_cursor_to_end(ledit_window *window) {
298 window->bb->line_cur_pos = window->bb->line_len;
299 window->redraw = 1;
300 }
301
302 /* FIXME: respect PangoLogAttr.backspace_deletes_character */
303 void
304 window_delete_bottom_bar_char(ledit_window *window, int dir) {
305 int byte = window->bb->line_cur_pos;
306 if (dir < 0) {
307 byte--;
308 while (byte > 0 &&
309 (window->bb->line_text[byte] & 0xC0) == 0x80) {
310 byte--;
311 }
312 if (byte < window->bb->min_pos)
313 byte = window->bb->min_pos;
314 memmove(
315 window->bb->line_text + byte,
316 window->bb->line_text + window->bb->line_cur_pos,
317 window->bb->line_len - window->bb->line_cur_pos
318 );
319 window->bb->line_len -= (window->bb->line_cur_pos - byte…
320 window->bb->line_cur_pos = byte;
321 } else if (dir > 0) {
322 byte++;
323 while (byte < window->bb->line_len &&
324 (window->bb->line_text[byte] & 0xC0) == 0x80) {
325 byte++;
326 }
327 if (byte >= window->bb->line_len)
328 byte = window->bb->line_len;
329 memmove(
330 window->bb->line_text + window->bb->line_cur_pos,
331 window->bb->line_text + byte,
332 window->bb->line_len - byte
333 );
334 window->bb->line_len -= (byte - window->bb->line_cur_pos…
335 }
336 window->bb->line_text[window->bb->line_len] = '\0';
337 redraw_line_text(window);
338 }
339
340 void
341 window_set_bottom_bar_cursor(ledit_window *window, int byte_pos) {
342 /* FIXME: check if valid? */
343 window->bb->line_cur_pos = byte_pos;
344 window->redraw = 1;
345 }
346
347 int
348 ledit_window_get_bottom_bar_cursor(ledit_window *window) {
349 return window->bb->line_cur_pos;
350 }
351
352 void
353 window_set_bottom_bar_text_shown(ledit_window *window, int shown) {
354 window->bottom_text_shown = shown;
355 window->redraw = 1;
356 if (shown) {
357 window->message_shown = 0;
358 pango_layout_set_width(window->bb->line, -1);
359 redraw_line_text(window);
360 recalc_text_size(window);
361 }
362 }
363
364 int
365 ledit_window_bottom_bar_text_shown(ledit_window *window) {
366 return window->bottom_text_shown;
367 }
368
369 void
370 window_set_bottom_bar_text(ledit_window *window, char *text, int len) {
371 window->bb->line_len = 0;
372 window->bb->line_cur_pos = 0;
373 window_insert_bottom_bar_text(window, text, len);
374 window->redraw = 1;
375 }
376
377 void
378 window_set_bottom_bar_realtext(ledit_window *window, char *text, int len…
379 if (window->bb->min_pos <= window->bb->line_len)
380 window->bb->line_len = window->bb->min_pos;
381 window->bb->line_cur_pos = window->bb->line_len;
382 window_insert_bottom_bar_text(window, text, len);
383 window->redraw = 1;
384 }
385
386 char *
387 window_get_bottom_bar_text(ledit_window *window) {
388 return window->bb->line_text;
389 }
390
391 void
392 window_show_message(ledit_window *window, char *text, int len) {
393 pango_layout_set_width(window->bb->line, window->w * PANGO_SCALE…
394 window_set_bottom_bar_text(window, text, len);
395 /* FIXME: rename these */
396 window->bottom_text_shown = 0;
397 window->message_shown = 1;
398 window->redraw = 1;
399 }
400
401 void
402 window_show_message_fmt(ledit_window *window, char *fmt, ...) {
403 va_list args;
404 va_start(args, fmt);
405 int len = vsnprintf(window->bb->line_text, window->bb->line_allo…
406 if (len >= window->bb->line_alloc) {
407 va_end(args);
408 va_start(args, fmt);
409 /* +1 because of terminating '\0' */
410 resize_line_text(window, len + 1);
411 vsnprintf(window->bb->line_text, window->bb->line_alloc,…
412 }
413 window->bb->line_len = len;
414 va_end(args);
415 pango_layout_set_width(window->bb->line, window->w * PANGO_SCALE…
416 window->bottom_text_shown = 0;
417 window->message_shown = 1;
418 redraw_line_text(window);
419 }
420
421 int
422 window_message_shown(ledit_window *window) {
423 return window->message_shown;
424 }
425
426 void
427 window_hide_message(ledit_window *window) {
428 window->message_shown = 0;
429 window->redraw = 1;
430 recalc_text_size(window);
431 }
432
433 /* FIXME: give these functions more sensible names */
434 static void
435 get_scroll_pos_height(ledit_window *window, double *pos_ret, double *hei…
436 *height_ret = ((double)window->text_h / window->scroll_max) * wi…
437 *pos_ret = (window->scroll_offset /
438 (window->scroll_max - window->text_h)) * (window->text_h …
439 }
440
441 static void
442 set_scroll_pos(ledit_window *window, double pos) {
443 window->scroll_offset = pos * (window->scroll_max / (double)wind…
444 if (window->scroll_offset < 0)
445 window->scroll_offset = 0;
446 if (window->scroll_offset + window->text_h > window->scroll_max)
447 window->scroll_offset = window->scroll_max - window->tex…
448 /* FIXME: check for overflow */
449 if (window->scroll_callback)
450 window->scroll_callback(window->scroll_cb_data, (long)wi…
451 window->redraw = 1;
452 }
453
454 void
455 window_set_scroll_max(ledit_window *window, long max) {
456 window->scroll_max = max;
457 window->redraw = 1;
458 }
459
460 void
461 window_set_scroll_pos(ledit_window *window, long pos) {
462 window->scroll_offset = pos;
463 window->redraw = 1;
464 }
465
466 void
467 window_set_scroll_callback(ledit_window *window, void (*cb)(void *, long…
468 window->scroll_callback = cb;
469 window->scroll_cb_data = data;
470 }
471
472 void
473 window_set_button_callback(ledit_window *window, void (*cb)(void *, XEve…
474 window->button_callback = cb;
475 window->button_cb_data = data;
476 }
477
478 void
479 window_set_resize_callback(ledit_window *window, void (*cb)(void *), voi…
480 window->resize_callback = cb;
481 window->resize_cb_data = data;
482 }
483
484 /* FIXME: Change naming convention to fit the rest of ledit */
485 /* FIXME: It's a bit weird when an input box pops up during normal mode.
486 Can/should this be disabled? */
487 int ximopen(ledit_window *window, Display *dpy);
488 void ximinstantiate(Display *dpy, XPointer client, XPointer call);
489 void ximdestroy(XIM xim, XPointer client, XPointer call);
490 int xicdestroy(XIC xim, XPointer client, XPointer call);
491
492 /* blatantly stolen from st */
493 int
494 ximopen(ledit_window *window, Display *dpy)
495 {
496 XIMCallback imdestroy = { .client_data = (XPointer)window, .call…
497 XICCallback icdestroy = { .client_data = (XPointer)window, .call…
498
499 window->xim = XOpenIM(dpy, NULL, NULL, NULL);
500 if (window->xim == NULL)
501 return 0;
502
503 if (XSetIMValues(window->xim, XNDestroyCallback, &imdestroy, NUL…
504 fprintf(
505 stderr, "XSetIMValues: Could not set XNDestroyCallba…
506 );
507 }
508
509 window->spotlist = XVaCreateNestedList(0, XNSpotLocation, &windo…
510
511 if (window->xic == NULL) {
512 window->xic = XCreateIC(
513 window->xim, XNInputStyle,
514 XIMPreeditNothing | XIMStatusNothing,
515 XNClientWindow, window->xwin,
516 XNDestroyCallback, &icdestroy, NULL
517 );
518 }
519 if (window->xic == NULL)
520 fprintf(stderr, "XCreateIC: Could not create input conte…
521
522 return 1;
523 }
524
525 void
526 ximinstantiate(Display *dpy, XPointer client, XPointer call)
527 {
528 (void)call;
529 ledit_window *window = (ledit_window *)client;
530 if (ximopen(window, dpy)) {
531 XUnregisterIMInstantiateCallback(
532 dpy, NULL, NULL, NULL, ximinstantiate, (XPointer)win…
533 );
534 }
535 }
536
537 void
538 ximdestroy(XIM xim, XPointer client, XPointer call)
539 {
540 (void)xim;
541 (void)call;
542 ledit_window *window = (ledit_window *)client;
543 window->xim = NULL;
544 XRegisterIMInstantiateCallback(
545 window->common->dpy, NULL, NULL, NULL, ximinstantiate, (XPoi…
546 );
547 XFree(window->spotlist);
548 }
549
550 int
551 xicdestroy(XIC xim, XPointer client, XPointer call)
552 {
553 (void)xim;
554 (void)call;
555 ledit_window *window = (ledit_window *)client;
556 window->xic = NULL;
557 return 1;
558 }
559
560 void
561 xximspot(ledit_window *window, int x, int y) {
562 if (window->xic == NULL)
563 return;
564 /* FIXME! */
565 window->spot.x = x;
566 window->spot.y = y;
567 XSetICValues(window->xic, XNPreeditAttributes, window->spotlist,…
568 }
569
570 static struct bb_item *
571 push_bb_item(ledit_window *window) {
572 if (window->bb->items_num == window->bb->items_alloc) {
573 size_t new_alloc = ideal_array_size(window->bb->items_al…
574 window->bb->items = ledit_reallocarray(window->bb->items…
575 window->bb->items_alloc = new_alloc;
576 }
577 struct bb_item *item = &window->bb->items[window->bb->items_num];
578 item->layout = pango_layout_new(window->context);
579 pango_layout_set_font_description(item->layout, window->font);
580 item->draw = draw_create(window, 10, 10);
581 item->w = item->h = 0;
582 window->bb->items_num++;
583 return item;
584 }
585
586 ledit_window *
587 window_create(ledit_common *common, ledit_clipboard *clipboard) {
588 XGCValues gcv;
589
590 ledit_theme *theme = config_get_theme();
591
592 ledit_window *window = ledit_malloc(sizeof(ledit_window));
593 window->first_resize = 1;
594
595 window->scroll_dragging = 0;
596 window->scroll_grab_handle = 0;
597 window->w = 500;
598 window->h = 500;
599 window->scroll_callback = NULL;
600 window->button_callback = NULL;
601 window->resize_callback = NULL;
602 window->scroll_cb_data = NULL;
603 window->button_cb_data = NULL;
604 window->resize_cb_data = NULL;
605
606 memset(&window->wattrs, 0, sizeof(window->wattrs));
607 window->wattrs.background_pixel = theme->text_bg.pixel;
608 window->wattrs.colormap = common->cm;
609 /* this causes the window contents to be kept
610 * when it is resized, leading to less flicker */
611 window->wattrs.bit_gravity = NorthWestGravity;
612 /* FIXME: FocusChangeMask? */
613 window->wattrs.event_mask = KeyPressMask |
614 ExposureMask | VisibilityChangeMask | StructureNotifyMask |
615 PointerMotionMask | ButtonPressMask | ButtonReleaseMask;
616 window->xwin = XCreateWindow(
617 common->dpy, DefaultRootWindow(common->dpy), 0, 0,
618 window->w, window->h, 0, common->depth,
619 InputOutput, common->vis,
620 CWBackPixel | CWColormap | CWBitGravity | CWEventMask, &wind…
621 );
622 XSetStandardProperties(common->dpy, window->xwin, "ledit", NULL,…
623
624 window->back_buf = XdbeAllocateBackBufferName(
625 common->dpy, window->xwin, XdbeBackground
626 );
627 window->drawable = window->back_buf;
628
629 memset(&gcv, 0, sizeof(gcv));
630 gcv.line_width = 1;
631 window->gc = XCreateGC(common->dpy, window->back_buf, GCLineWidt…
632
633 /* FIXME: move to common */
634 window->fontmap = pango_xft_get_font_map(common->dpy, common->sc…
635 window->context = pango_font_map_create_context(window->fontmap);
636
637 window->font = pango_font_description_from_string(theme->text_fo…
638 pango_font_description_set_size(window->font, theme->text_size *…
639
640 window->wm_delete_msg = XInternAtom(common->dpy, "WM_DELETE_WIND…
641 XSetWMProtocols(common->dpy, window->xwin, &window->wm_delete_ms…
642
643 window->common = common;
644 /* FIXME: not used yet - this will be used later when clipboard …
645 window->clipboard = clipboard;
646
647 window->bb = ledit_malloc(sizeof(bottom_bar));
648 window->bb->items = NULL;
649 window->bb->items_num = window->bb->items_alloc = 0;
650 window->bb->w_per_sep = 0;
651 window->bb->line = pango_layout_new(window->context);
652 pango_layout_set_font_description(window->bb->line, window->font…
653 pango_layout_set_wrap(window->bb->line, PANGO_WRAP_WORD_CHAR);
654 #if PANGO_VERSION_CHECK(1, 44, 0)
655 PangoAttrList *pattrs = pango_attr_list_new();
656 PangoAttribute *no_hyphens = pango_attr_insert_hyphens_new(FALSE…
657 pango_attr_list_insert(pattrs, no_hyphens);
658 pango_layout_set_attributes(window->bb->line, pattrs);
659 pango_attr_list_unref(pattrs);
660 #endif
661 window->bb->line_draw = draw_create(window, 10, 10);
662 window->bb->line_w = window->bb->line_h = 10;
663 window->bb->line_text = NULL;
664 window->bb->line_alloc = window->bb->line_len = 0;
665 window->bb->line_cur_pos = 0;
666 window->bb->min_pos = 0;
667 window->bottom_text_shown = 0;
668 window->message_shown = 0;
669
670 window->xim = NULL;
671 window->xic = NULL;
672 if (!ximopen(window, common->dpy)) {
673 XRegisterIMInstantiateCallback(
674 common->dpy, NULL, NULL, NULL,
675 ximinstantiate, (XPointer)window
676 );
677 }
678
679 XMapWindow(common->dpy, window->xwin);
680
681 window->cursor_text = XCreateFontCursor(window->common->dpy, XC_…
682 /* FIXME: maybe delay this (i.e. move to different function)? */
683 XMapWindow(common->dpy, window->xwin);
684
685 window->redraw = 1;
686 struct timespec now;
687 clock_gettime(CLOCK_MONOTONIC, &now);
688 window->last_scroll = now;
689 window->last_motion = now;
690 window->last_resize = now;
691 window->last_scroll_valid = 0;
692 window->last_motion_valid = 0;
693 window->last_resize_valid = 0;
694 window->scroll_num = 0;
695
696 /* setup format for bottom bar */
697 /* FIXME: this seems ugly, there's probably a better way
698 also, it might still be buggy */
699 char *fmt = ledit_strdup(theme->bar_fmt);
700 int offset = 0;
701 int in_text = 0;
702 int start = 0;
703 size_t i = 0;
704 struct bb_item *item = NULL;
705 for (; fmt[i] != '\0'; i++) {
706 if (fmt[i] == '%') {
707 i++;
708 if (fmt[i] == '%') {
709 if (!in_text) {
710 start = i;
711 offset = 0;
712 in_text = 1;
713 } else {
714 offset++;
715 }
716 } else {
717 if (in_text) {
718 item = push_bb_item(window);
719 item->type = BB_STR;
720 fmt[i - 1 - offset] = '\0';
721 set_item_text(window, theme, ite…
722 in_text = 0;
723 }
724 switch (fmt[i]) {
725 case 'l':
726 item = push_bb_item(window);
727 item->type = BB_LINE;
728 item->val.sz = SIZE_MAX;
729 break;
730 case 'b':
731 item = push_bb_item(window);
732 item->type = BB_BYTE;
733 item->val.sz = SIZE_MAX;
734 break;
735 case 'k':
736 item = push_bb_item(window);
737 item->type = BB_LANG;
738 item->val.sz = SIZE_MAX;
739 break;
740 case 'm':
741 item = push_bb_item(window);
742 item->type = BB_MODE;
743 item->val.m = VISUAL;
744 break;
745 case 'h':
746 item = push_bb_item(window);
747 item->type = BB_HLMODE;
748 item->val.i = -1;
749 break;
750 case 's':
751 /* FIXME: don't create layout an…
752 item = push_bb_item(window);
753 item->type = BB_SEP;
754 break;
755 default:
756 /* FIXME: better error reporting…
757 fprintf(stderr, "WARNING: Invali…
758 window_show_message(window, "Inv…
759 /* FIXME: it might make more sen…
760 but this is the easiest */
761 goto end;
762 }
763 }
764 } else if (!in_text) {
765 start = i;
766 offset = 0;
767 in_text = 1;
768 }
769 fmt[i - offset] = fmt[i];
770 }
771 if (in_text) {
772 item = push_bb_item(window);
773 item->type = BB_STR;
774 fmt[i - offset] = '\0';
775 set_item_text(window, theme, item, fmt + start);
776 }
777 end:
778 free(fmt);
779 window_set_format_args(window, NORMAL, 1, 1, 1, 0);
780
781 return window;
782 }
783
784 void
785 window_destroy(ledit_window *window) {
786 struct bb_item *items = window->bb->items;
787 for (size_t i = 0; i < window->bb->items_num; i++) {
788 if (items[i].layout)
789 g_object_unref(items[i].layout);
790 if (items[i].draw)
791 draw_destroy(window, items[i].draw);
792 }
793 free(window->bb->items);
794 /* FIXME: check what's still missing */
795 g_object_unref(window->bb->line);
796 draw_destroy(window, window->bb->line_draw);
797
798 pango_font_description_free(window->font);
799 /* FIXME: The pango documentation says that the context must be …
800 but the program segfaults when that is done. */
801 /*g_object_unref(window->context);*/
802 g_object_unref(window->fontmap);
803
804 XFreeGC(window->common->dpy, window->gc);
805 if (window->spotlist)
806 XFree(window->spotlist);
807 XDestroyWindow(window->common->dpy, window->xwin);
808
809 free(window->bb->line_text);
810 free(window->bb);
811 free(window);
812 }
813
814 void
815 window_clear(ledit_window *window) {
816 ledit_theme *theme = config_get_theme();
817 XSetForeground(window->common->dpy, window->gc, theme->text_bg.p…
818 XFillRectangle(
819 window->common->dpy, window->drawable, window->gc, 0, 0, win…
820 );
821 }
822
823 void
824 window_redraw(ledit_window *window) {
825 ledit_theme *t = config_get_theme();
826 if (window->scroll_max > window->text_h) {
827 XSetForeground(window->common->dpy, window->gc, t->scrol…
828 XFillRectangle(
829 window->common->dpy, window->drawable, window->gc,
830 window->w - t->scrollbar_width, 0, t->scrollbar_widt…
831 );
832 XSetForeground(window->common->dpy, window->gc, t->scrol…
833 double scroll_h, scroll_y;
834 get_scroll_pos_height(window, &scroll_y, &scroll_h);
835 XFillRectangle(
836 window->common->dpy, window->drawable, window->gc,
837 window->w - t->scrollbar_width, (int)round(scroll_y),
838 t->scrollbar_width, (int)round(scroll_h)
839 );
840 }
841 XSetForeground(window->common->dpy, window->gc, t->bar_bg.pixel);
842 XFillRectangle(
843 window->common->dpy, window->drawable, window->gc,
844 0, window->text_h,
845 window->w, window->h - window->text_h
846 );
847 if (window->message_shown) {
848 XCopyArea(
849 window->common->dpy, window->bb->line_draw->pixmap,
850 window->drawable, window->gc,
851 0, 0, window->bb->line_w, window->bb->line_h,
852 0, window->text_h
853 );
854 } else if (window->bottom_text_shown) {
855 XSetForeground(window->common->dpy, window->gc, t->bar_c…
856 /* move input method position to cursor and draw cursor …
857 PangoRectangle strong, weak;
858 pango_layout_get_cursor_pos(
859 window->bb->line, window->bb->line_cur_pos, &strong,…
860 );
861 /* FIXME: Is this the best position? The bottom of the l…
862 just the bottom of the window, so an input method box…
863 have to be moved out of the way anyways (fcitx just m…
864 up a bit so it sort of works) */
865 xximspot(window, strong.x / PANGO_SCALE, window->h);
866 int x = 0;
867 int w = window->bb->line_w;
868 int cur_x = strong.x / PANGO_SCALE;
869 if (w > window->w) {
870 /* FIXME: try to keep some space on the edges */
871 x = (cur_x / window->w) * window->w;
872 w = window->w;
873 if (x + w > window->bb->line_w)
874 w = window->bb->line_w - x;
875 }
876 XCopyArea(
877 window->common->dpy, window->bb->line_draw->pixmap,
878 window->drawable, window->gc,
879 x, 0, w, window->bb->line_h,
880 0, window->text_h
881 );
882 XDrawLine(
883 window->common->dpy, window->drawable, window->gc,
884 cur_x - x, window->text_h + strong.y / PANGO_SCALE,
885 cur_x - x,
886 window->text_h + (strong.y + strong.height) / PANGO_…
887 );
888 } else {
889 struct bb_item *items = window->bb->items;
890 int cur_x = 0;
891 for (size_t i = 0; i < window->bb->items_num; i++) {
892 if (items[i].type == BB_SEP) {
893 cur_x += window->bb->w_per_sep;
894 } else {
895 XCopyArea(
896 window->common->dpy, items[i].draw->…
897 window->drawable, window->gc,
898 0, 0, items[i].w, items[i].h,
899 cur_x, window->text_h
900 );
901 cur_x += items[i].w;
902 }
903 }
904 }
905
906 XdbeSwapInfo swap_info;
907 swap_info.swap_window = window->xwin;
908 swap_info.swap_action = XdbeBackground;
909
910 if (!XdbeSwapBuffers(window->common->dpy, &swap_info, 1))
911 exit(1);
912 XFlush(window->common->dpy);
913 window->redraw = 0;
914 }
915
916 void
917 window_get_textview_size(ledit_window *window, int *w_ret, int *h_ret) {
918 *w_ret = window->text_w;
919 *h_ret = window->text_h;
920 }
921
922 void
923 window_handle_filtered_events(ledit_window *window) {
924 struct timespec now, elapsed;
925 if (window->last_motion_valid) {
926 clock_gettime(CLOCK_MONOTONIC, &now);
927 ledit_timespecsub(&now, &window->last_motion, &elapsed);
928 if (elapsed.tv_sec > 0 || elapsed.tv_nsec >= MOUSE_TICK)…
929 window_drag_motion(window, &window->last_motion_…
930 window->last_motion = now;
931 window->last_motion_valid = 0;
932 }
933 }
934 if (window->last_scroll_valid) {
935 clock_gettime(CLOCK_MONOTONIC, &now);
936 ledit_timespecsub(&now, &window->last_scroll, &elapsed);
937 if (elapsed.tv_sec > 0 || elapsed.tv_nsec >= MOUSE_TICK)…
938 window_button_press(window, &window->last_scroll…
939 window->last_scroll = now;
940 window->last_scroll_valid = 0;
941 }
942 }
943 if (window->last_resize_valid) {
944 clock_gettime(CLOCK_MONOTONIC, &now);
945 ledit_timespecsub(&now, &window->last_resize, &elapsed);
946 if (window->first_resize || elapsed.tv_sec > 0 || elapse…
947 window_resize(
948 window,
949 window->last_resize_event.xconfigure.width,
950 window->last_resize_event.xconfigure.height
951 );
952 window->last_resize = now;
953 window->last_resize_valid = 0;
954 window->redraw = 1;
955 window->first_resize = 0;
956 }
957 }
958 }
959
960 void
961 window_resize(ledit_window *window, int w, int h) {
962 if (w == window->w && h == window->h)
963 return;
964 window->w = w;
965 window->h = h;
966 if (window->message_shown) {
967 pango_layout_set_width(window->bb->line, window->w * PAN…
968 redraw_line_text(window);
969 } else {
970 recalc_text_size(window);
971 }
972 if (window->resize_callback)
973 window->resize_callback(window->resize_cb_data);
974 window->redraw = 1;
975 }
976
977 void
978 window_register_button_press(ledit_window *window, XEvent *event) {
979 int scroll_delta;
980 if (event->xbutton.button == Button4 ||
981 event->xbutton.button == Button5) {
982 scroll_delta = event->xbutton.button == Button4 ? -1 : 1;
983 if (window->last_scroll_valid) {
984 window->scroll_num += scroll_delta;
985 } else {
986 window->last_scroll_event = *event;
987 window->last_scroll_valid = 1;
988 window->scroll_num = scroll_delta;
989 }
990 } else {
991 window_button_press(window, event, 0);
992 }
993 }
994
995 void
996 window_register_resize(ledit_window *window, XEvent *event) {
997 window->last_resize_event = *event;
998 window->last_resize_valid = 1;
999 }
1000
1001 void
1002 window_register_motion(ledit_window *window, XEvent *event) {
1003 /* cursor should always change, even if time has not elapsed */
1004 int x = event->xmotion.x;
1005 int y = event->xmotion.y;
1006 /* FIXME: avoid these calls if nothing has changed */
1007 if (x < window->text_w && y < window->text_h)
1008 XDefineCursor(window->common->dpy, window->xwin, window-…
1009 else
1010 XDefineCursor(window->common->dpy, window->xwin, None);
1011 window->last_motion_event = *event;
1012 window->last_motion_valid = 1;
1013 }
1014
1015 /* FIXME: make button handling more consistent */
1016 /* FIXME: improve set_scroll_pos; make it a bit clearer */
1017 void
1018 window_button_press(ledit_window *window, XEvent *event, int scroll_num)…
1019 ledit_theme *theme = config_get_theme();
1020 int x = event->xbutton.x;
1021 int y = event->xbutton.y;
1022 double scroll_h, scroll_y;
1023 switch (event->xbutton.button) {
1024 case Button1:
1025 get_scroll_pos_height(window, &scroll_y, &scroll…
1026 if (x >= window->text_w) {
1027 window->scroll_dragging = 1;
1028 window->scroll_grab_handle = y;
1029 if (y < scroll_y || y > scroll_y + scrol…
1030 double new_scroll_y = y - scroll…
1031 set_scroll_pos(window, new_scrol…
1032 }
1033 window->redraw = 1;
1034 } else if (y < window->text_h) {
1035 if (window->button_callback)
1036 window->button_callback(window->…
1037 window->redraw = 1;
1038 }
1039 break;
1040 case Button2:
1041 if (x < window->text_w && y < window->text_h && …
1042 window->button_callback(window->button_c…
1043 break;
1044 case Button4:
1045 case Button5:
1046 window->scroll_offset += scroll_num * theme->scr…
1047 if (window->scroll_offset < 0)
1048 window->scroll_offset = 0;
1049 if (window->scroll_offset + window->text_h > win…
1050 window->scroll_offset = window->scroll_m…
1051 }
1052 if (window->scroll_callback)
1053 window->scroll_callback(window->scroll_c…
1054 window->redraw = 1;
1055 }
1056 }
1057
1058 void
1059 window_button_release(ledit_window *window, XEvent *event) {
1060 int x = event->xbutton.x;
1061 int y = event->xbutton.y;
1062 int in_text = x < window->text_w && y < window->text_h;
1063 if (event->xbutton.button == Button1) {
1064 window->scroll_dragging = 0;
1065 if (in_text && window->button_callback)
1066 window->button_callback(window->button_cb_data, …
1067 window->redraw = 1;
1068 } else if (event->xbutton.button == Button2 && in_text && window…
1069 window->button_callback(window->button_cb_data, event);
1070 }
1071 }
1072
1073 void
1074 window_drag_motion(ledit_window *window, XEvent *event) {
1075 if (window->scroll_dragging) {
1076 double scroll_h, scroll_y;
1077 get_scroll_pos_height(window, &scroll_y, &scroll_h);
1078 scroll_y += event->xmotion.y - window->scroll_grab_handl…
1079 window->scroll_grab_handle = event->xmotion.y;
1080 set_scroll_pos(window, scroll_y);
1081 window->redraw = 1;
1082 } else {
1083 if (window->button_callback)
1084 window->button_callback(window->button_cb_data, …
1085 window->redraw = 1;
1086 }
1087 }
You are viewing proxied material from lumidify.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.