mirror of
https://github.com/davatorium/rofi.git
synced 2024-11-18 13:54:36 -05:00
Use cairo to do drawing.
This commit is contained in:
parent
29e81fdb07
commit
8f1f03e6d2
9 changed files with 398 additions and 424 deletions
|
@ -9,19 +9,19 @@ bin_PROGRAMS=rofi
|
||||||
dist_bin_SCRIPTS=script/rofi-sensible-terminal
|
dist_bin_SCRIPTS=script/rofi-sensible-terminal
|
||||||
|
|
||||||
LIBS=\
|
LIBS=\
|
||||||
@xft_LIBS@\
|
|
||||||
@x11_LIBS@\
|
@x11_LIBS@\
|
||||||
@xinerama_LIBS@\
|
@xinerama_LIBS@\
|
||||||
@libsn_LIBS@\
|
@libsn_LIBS@\
|
||||||
@pango_LIBS@
|
@pango_LIBS@\
|
||||||
|
@cairo_LIBS@
|
||||||
|
|
||||||
AM_CFLAGS=\
|
AM_CFLAGS=\
|
||||||
@EXTRA_CFLAGS@\
|
@EXTRA_CFLAGS@\
|
||||||
@xft_CFLAGS@\
|
|
||||||
@x11_CFLAGS@\
|
@x11_CFLAGS@\
|
||||||
@xinerama_CFLAGS@\
|
@xinerama_CFLAGS@\
|
||||||
@pango_CFLAGS@\
|
@pango_CFLAGS@\
|
||||||
@libsn_CFLAGS@\
|
@libsn_CFLAGS@\
|
||||||
|
@cairo_CFLAGS@\
|
||||||
-DMANPAGE_PATH="\"$(mandir)/\""\
|
-DMANPAGE_PATH="\"$(mandir)/\""\
|
||||||
-I$(top_srcdir)/include/\
|
-I$(top_srcdir)/include/\
|
||||||
-I$(top_srcdir)/config/\
|
-I$(top_srcdir)/config/\
|
||||||
|
|
|
@ -48,10 +48,10 @@ AS_IF([test "x$enable_i3support" != xno && test "x$enable_windowmode" != "xno"],
|
||||||
##
|
##
|
||||||
PKG_PROG_PKG_CONFIG
|
PKG_PROG_PKG_CONFIG
|
||||||
|
|
||||||
PKG_CHECK_MODULES([xft], [xft])
|
|
||||||
PKG_CHECK_MODULES([x11], [x11])
|
PKG_CHECK_MODULES([x11], [x11])
|
||||||
PKG_CHECK_MODULES([xinerama], [xinerama])
|
PKG_CHECK_MODULES([xinerama], [xinerama])
|
||||||
PKG_CHECK_MODULES([pango], [pango pangoxft])
|
PKG_CHECK_MODULES([pango], [pango pangocairo])
|
||||||
|
PKG_CHECK_MODULES([cairo], [cairo cairo-xlib])
|
||||||
PKG_CHECK_MODULES([libsn], [libstartup-notification-1.0])
|
PKG_CHECK_MODULES([libsn], [libstartup-notification-1.0])
|
||||||
|
|
||||||
AC_SUBST([EXTRA_CFLAGS], ["-Wall -Wextra -Wparentheses -Winline -pedantic"])
|
AC_SUBST([EXTRA_CFLAGS], ["-Wall -Wextra -Wparentheses -Winline -pedantic"])
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
#define ROFI_MAIN_H
|
#define ROFI_MAIN_H
|
||||||
#include <X11/X.h>
|
#include <X11/X.h>
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <textbox.h>
|
#include <textbox.h>
|
||||||
#include "keyb.h"
|
#include "keyb.h"
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,12 @@
|
||||||
#ifndef ROFI_SCROLLBAR_H
|
#ifndef ROFI_SCROLLBAR_H
|
||||||
#define ROFI_SCROLLBAR_H
|
#define ROFI_SCROLLBAR_H
|
||||||
|
#include <cairo.h>
|
||||||
/**
|
/**
|
||||||
* Internal structure for the scrollbar.
|
* Internal structure for the scrollbar.
|
||||||
*/
|
*/
|
||||||
typedef struct _scrollbar
|
typedef struct _scrollbar
|
||||||
{
|
{
|
||||||
Window window, parent;
|
|
||||||
short x, y, w, h;
|
short x, y, w, h;
|
||||||
GC gc;
|
|
||||||
unsigned int length;
|
unsigned int length;
|
||||||
unsigned int pos;
|
unsigned int pos;
|
||||||
unsigned int pos_length;
|
unsigned int pos_length;
|
||||||
|
@ -27,22 +25,7 @@ typedef struct _scrollbar
|
||||||
*
|
*
|
||||||
* @returns the scrollbar object.
|
* @returns the scrollbar object.
|
||||||
*/
|
*/
|
||||||
scrollbar *scrollbar_create ( Window parent, XVisualInfo *vinfo, Colormap map,
|
scrollbar *scrollbar_create ( short x, short y, short w, short h );
|
||||||
short x, short y, short w, short h );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param sb scrollbar object
|
|
||||||
*
|
|
||||||
* Hide (unmap) the scrollbar.
|
|
||||||
*/
|
|
||||||
void scrollbar_hide ( scrollbar *sb );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param sb scrollbar object
|
|
||||||
*
|
|
||||||
* Show (map) the scrollbar.
|
|
||||||
*/
|
|
||||||
void scrollbar_show ( scrollbar *sb );
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param sb scrollbar object
|
* @param sb scrollbar object
|
||||||
|
@ -80,7 +63,7 @@ void scrollbar_set_max_value ( scrollbar *sb, unsigned int max );
|
||||||
*
|
*
|
||||||
* Draw the scrollbar, used after expose event or update
|
* Draw the scrollbar, used after expose event or update
|
||||||
*/
|
*/
|
||||||
void scrollbar_draw ( scrollbar *sb );
|
void scrollbar_draw ( scrollbar *sb, cairo_t *draw );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param sb scrollbar object
|
* @param sb scrollbar object
|
||||||
|
|
|
@ -1,24 +1,34 @@
|
||||||
#ifndef ROFI_TEXTBOX_H
|
#ifndef ROFI_TEXTBOX_H
|
||||||
#define ROFI_TEXTBOX_H
|
#define ROFI_TEXTBOX_H
|
||||||
|
|
||||||
|
#include <X11/Xutil.h>
|
||||||
#include <pango/pango.h>
|
#include <pango/pango.h>
|
||||||
#include <pango/pangoxft.h>
|
|
||||||
#include <pango/pango-fontmap.h>
|
#include <pango/pango-fontmap.h>
|
||||||
|
#include <cairo.h>
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
double red, green, blue, alpha;
|
||||||
Window window, parent;
|
} Color;
|
||||||
short x, y, w, h;
|
|
||||||
short cursor;
|
typedef struct
|
||||||
XftColor color_fg, color_bg;
|
{
|
||||||
char *text;
|
unsigned long flags;
|
||||||
XIM xim;
|
short x, y, w, h;
|
||||||
XIC xic;
|
short cursor;
|
||||||
PangoLayout *layout;
|
Color color_fg, color_bg;
|
||||||
int tbft;
|
char *text;
|
||||||
int markup;
|
XIM xim;
|
||||||
int changed;
|
XIC xic;
|
||||||
|
PangoLayout *layout;
|
||||||
|
int tbft;
|
||||||
|
int markup;
|
||||||
|
int changed;
|
||||||
|
|
||||||
|
cairo_surface_t *main_surface;
|
||||||
|
cairo_t *main_draw;
|
||||||
|
|
||||||
|
int update;
|
||||||
} textbox;
|
} textbox;
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
|
@ -49,10 +59,7 @@ typedef enum
|
||||||
STATE_MASK = ~( ALT | HIGHLIGHT )
|
STATE_MASK = ~( ALT | HIGHLIGHT )
|
||||||
} TextBoxFontType;
|
} TextBoxFontType;
|
||||||
|
|
||||||
textbox* textbox_create ( Window parent,
|
textbox* textbox_create ( TextboxFlags flags,
|
||||||
XVisualInfo *vinfo,
|
|
||||||
Colormap map,
|
|
||||||
TextboxFlags flags,
|
|
||||||
short x, short y, short w, short h,
|
short x, short y, short w, short h,
|
||||||
TextBoxFontType tbft,
|
TextBoxFontType tbft,
|
||||||
const char *text );
|
const char *text );
|
||||||
|
@ -79,19 +86,12 @@ void textbox_font ( textbox *tb, TextBoxFontType tbft );
|
||||||
*/
|
*/
|
||||||
void textbox_text ( textbox *tb, const char *text );
|
void textbox_text ( textbox *tb, const char *text );
|
||||||
|
|
||||||
/**
|
|
||||||
* @param tb Handle to the textbox
|
|
||||||
*
|
|
||||||
* Show the textbox (map window)
|
|
||||||
*/
|
|
||||||
void textbox_show ( textbox *tb );
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param tb Handle to the textbox
|
* @param tb Handle to the textbox
|
||||||
*
|
*
|
||||||
* Render the textbox.
|
* Render the textbox.
|
||||||
*/
|
*/
|
||||||
void textbox_draw ( textbox * tb );
|
void textbox_draw ( textbox *tb, cairo_t *draw );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param tb Handle to the textbox
|
* @param tb Handle to the textbox
|
||||||
|
@ -101,7 +101,7 @@ void textbox_draw ( textbox * tb );
|
||||||
*
|
*
|
||||||
* @returns if the key was handled (1), unhandled(0) or handled and return was pressed (-1)
|
* @returns if the key was handled (1), unhandled(0) or handled and return was pressed (-1)
|
||||||
*/
|
*/
|
||||||
int textbox_keypress ( textbox *tb, XEvent *ev );
|
int textbox_keypress ( textbox *tb, XIC xic, XEvent *ev );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param tb Handle to the textbox
|
* @param tb Handle to the textbox
|
||||||
|
@ -137,21 +137,11 @@ void textbox_move ( textbox *tb, int x, int y );
|
||||||
void textbox_insert ( textbox *tb, int pos, char *str );
|
void textbox_insert ( textbox *tb, int pos, char *str );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param tb Handle to the textbox
|
|
||||||
*
|
|
||||||
* Unmap the textbox window. Effectively hiding it.
|
|
||||||
*/
|
|
||||||
void textbox_hide ( textbox *tb );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param visual Information about the visual to target
|
|
||||||
* @param colormap The colormap to set the colors for.
|
|
||||||
*
|
|
||||||
* Setup the cached fonts. This is required to do
|
* Setup the cached fonts. This is required to do
|
||||||
* before any of the textbox_ functions is called.
|
* before any of the textbox_ functions is called.
|
||||||
* Clean with textbox_cleanup()
|
* Clean with textbox_cleanup()
|
||||||
*/
|
*/
|
||||||
void textbox_setup ( XVisualInfo *visual, Colormap colormap );
|
void textbox_setup ( void );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cleanup the allocated colors and fonts by textbox_setup().
|
* Cleanup the allocated colors and fonts by textbox_setup().
|
||||||
|
|
283
source/rofi.c
283
source/rofi.c
|
@ -44,6 +44,9 @@
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <cairo.h>
|
||||||
|
#include <cairo-xlib.h>
|
||||||
|
|
||||||
#define SN_API_NOT_YET_FROZEN
|
#define SN_API_NOT_YET_FROZEN
|
||||||
#include <libsn/sn.h>
|
#include <libsn/sn.h>
|
||||||
|
|
||||||
|
@ -70,14 +73,14 @@ typedef struct _Mode
|
||||||
|
|
||||||
// Pidfile.
|
// Pidfile.
|
||||||
extern Atom netatoms[NUM_NETATOMS];
|
extern Atom netatoms[NUM_NETATOMS];
|
||||||
char *pidfile = NULL;
|
char *pidfile = NULL;
|
||||||
const char *cache_dir = NULL;
|
const char *cache_dir = NULL;
|
||||||
SnDisplay *sndisplay = NULL;
|
SnDisplay *sndisplay = NULL;
|
||||||
SnLauncheeContext *sncontext = NULL;
|
SnLauncheeContext *sncontext = NULL;
|
||||||
Display *display = NULL;
|
Display *display = NULL;
|
||||||
char *display_str = NULL;
|
char *display_str = NULL;
|
||||||
Window main_window = None;
|
Window main_window = None;
|
||||||
GC gc = NULL;
|
// GC gc = NULL;
|
||||||
Colormap map = None;
|
Colormap map = None;
|
||||||
unsigned int normal_window_mode = FALSE;
|
unsigned int normal_window_mode = FALSE;
|
||||||
// Array of switchers.
|
// Array of switchers.
|
||||||
|
@ -87,6 +90,11 @@ unsigned int num_switchers = 0;
|
||||||
unsigned int curr_switcher = 0;
|
unsigned int curr_switcher = 0;
|
||||||
XVisualInfo vinfo;
|
XVisualInfo vinfo;
|
||||||
|
|
||||||
|
cairo_surface_t *surface = NULL;
|
||||||
|
cairo_t *draw = NULL;
|
||||||
|
XIM xim;
|
||||||
|
XIC xic;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param name Name of the switcher to lookup.
|
* @param name Name of the switcher to lookup.
|
||||||
*
|
*
|
||||||
|
@ -188,44 +196,6 @@ static int levenshtein ( const char *s, const char *t )
|
||||||
return dist ( s, t, d, ls, lt, 0, 0 );
|
return dist ( s, t, d, ls, lt, 0, 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
static Window create_window ( Display *display )
|
|
||||||
{
|
|
||||||
XSetWindowAttributes attr;
|
|
||||||
attr.colormap = map;
|
|
||||||
attr.border_pixel = color_border ( display );
|
|
||||||
attr.background_pixel = color_background ( display );
|
|
||||||
|
|
||||||
Window box = XCreateWindow ( display, DefaultRootWindow ( display ), 0, 0, 200, 100, config.menu_bw, vinfo.depth, InputOutput,
|
|
||||||
vinfo.visual, CWColormap | CWBorderPixel | CWBackPixel, &attr );
|
|
||||||
XSelectInput ( display, box, KeyReleaseMask | KeyPressMask | ExposureMask | ButtonPressMask | StructureNotifyMask | FocusChangeMask );
|
|
||||||
|
|
||||||
gc = XCreateGC ( display, box, 0, 0 );
|
|
||||||
int line_style = LineOnOffDash;
|
|
||||||
if ( strcasecmp ( config.separator_style, "dash" ) == 0 ) {
|
|
||||||
line_style = LineOnOffDash;
|
|
||||||
}
|
|
||||||
else if ( strcasecmp ( config.separator_style, "solid" ) == 0 ) {
|
|
||||||
line_style = LineSolid;
|
|
||||||
}
|
|
||||||
XSetLineAttributes ( display, gc, 2, line_style, CapButt, JoinMiter );
|
|
||||||
XSetForeground ( display, gc, color_separator ( display ) );
|
|
||||||
// make it an unmanaged window
|
|
||||||
if ( !normal_window_mode ) {
|
|
||||||
window_set_atom_prop ( display, box, netatoms[_NET_WM_STATE], &netatoms[_NET_WM_STATE_ABOVE], 1 );
|
|
||||||
XSetWindowAttributes sattr = { .override_redirect = True };
|
|
||||||
XChangeWindowAttributes ( display, box, CWOverrideRedirect, &sattr );
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
window_set_atom_prop ( display, box, netatoms[_NET_WM_WINDOW_TYPE], &netatoms[_NET_WM_WINDOW_TYPE_NORMAL], 1 );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the WM_NAME
|
|
||||||
XStoreName ( display, box, "rofi" );
|
|
||||||
|
|
||||||
x11_set_window_opacity ( display, box, config.window_opacity );
|
|
||||||
return box;
|
|
||||||
}
|
|
||||||
|
|
||||||
// State of the menu.
|
// State of the menu.
|
||||||
|
|
||||||
typedef struct MenuState
|
typedef struct MenuState
|
||||||
|
@ -278,6 +248,47 @@ typedef struct MenuState
|
||||||
int line_height;
|
int line_height;
|
||||||
}MenuState;
|
}MenuState;
|
||||||
|
|
||||||
|
static Window create_window ( Display *display )
|
||||||
|
{
|
||||||
|
XSetWindowAttributes attr;
|
||||||
|
attr.colormap = map;
|
||||||
|
attr.border_pixel = color_border ( display );
|
||||||
|
attr.background_pixel = color_background ( display );
|
||||||
|
|
||||||
|
Window box = XCreateWindow ( display, DefaultRootWindow ( display ), 0, 0, 200, 100, config.menu_bw, vinfo.depth, InputOutput,
|
||||||
|
vinfo.visual, CWColormap | CWBorderPixel | CWBackPixel, &attr );
|
||||||
|
XSelectInput (
|
||||||
|
display,
|
||||||
|
box,
|
||||||
|
KeyReleaseMask | KeyPressMask | ExposureMask | ButtonPressMask | StructureNotifyMask | FocusChangeMask |
|
||||||
|
Button1MotionMask );
|
||||||
|
|
||||||
|
surface = cairo_xlib_surface_create ( display, box, vinfo.visual, 200, 100 );
|
||||||
|
// Create a drawable.
|
||||||
|
draw = cairo_create ( surface );
|
||||||
|
cairo_set_operator ( draw, CAIRO_OPERATOR_SOURCE );
|
||||||
|
|
||||||
|
// // make it an unmanaged window
|
||||||
|
if ( !normal_window_mode ) {
|
||||||
|
window_set_atom_prop ( display, box, netatoms[_NET_WM_STATE], &netatoms[_NET_WM_STATE_ABOVE], 1 );
|
||||||
|
XSetWindowAttributes sattr = { .override_redirect = True };
|
||||||
|
XChangeWindowAttributes ( display, box, CWOverrideRedirect, &sattr );
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
window_set_atom_prop ( display, box, netatoms[_NET_WM_WINDOW_TYPE], &netatoms[_NET_WM_WINDOW_TYPE_NORMAL], 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
xim = XOpenIM ( display, NULL, NULL, NULL );
|
||||||
|
xic = XCreateIC ( xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNClientWindow,
|
||||||
|
box, XNFocusWindow, box, NULL );
|
||||||
|
|
||||||
|
// Set the WM_NAME
|
||||||
|
XStoreName ( display, box, "rofi" );
|
||||||
|
|
||||||
|
x11_set_window_opacity ( display, box, config.window_opacity );
|
||||||
|
return box;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param state Internal state of the menu.
|
* @param state Internal state of the menu.
|
||||||
*
|
*
|
||||||
|
@ -632,6 +643,26 @@ static void menu_keyboard_navigation ( MenuState *state, KeySym key, unsigned in
|
||||||
* mouse navigation through the elements.
|
* mouse navigation through the elements.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
static int intersect ( textbox *tb, int x, int y )
|
||||||
|
{
|
||||||
|
if ( x >= ( tb->x ) && x < ( tb->x + tb->w ) ) {
|
||||||
|
if ( y >= ( tb->y ) && y < ( tb->y + tb->h ) ) {
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
static int sb_intersect ( scrollbar *tb, int x, int y )
|
||||||
|
{
|
||||||
|
if ( x >= ( tb->x ) && x < ( tb->x + tb->w ) ) {
|
||||||
|
if ( y >= ( tb->y ) && y < ( tb->y + tb->h ) ) {
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
static void menu_mouse_navigation ( MenuState *state, XButtonEvent *xbe )
|
static void menu_mouse_navigation ( MenuState *state, XButtonEvent *xbe )
|
||||||
{
|
{
|
||||||
// Scroll event
|
// Scroll event
|
||||||
|
@ -651,13 +682,13 @@ static void menu_mouse_navigation ( MenuState *state, XButtonEvent *xbe )
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if ( state->scrollbar && state->scrollbar->window == xbe->window ) {
|
if ( state->scrollbar && sb_intersect ( state->scrollbar, xbe->x, xbe->y ) ) {
|
||||||
state->selected = scrollbar_clicked ( state->scrollbar, xbe->y );
|
state->selected = scrollbar_clicked ( state->scrollbar, xbe->y );
|
||||||
state->update = TRUE;
|
state->update = TRUE;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for ( unsigned int i = 0; config.sidebar_mode == TRUE && i < num_switchers; i++ ) {
|
for ( unsigned int i = 0; config.sidebar_mode == TRUE && i < num_switchers; i++ ) {
|
||||||
if ( switchers[i].tb->window == ( xbe->window ) ) {
|
if ( intersect ( switchers[i].tb, xbe->x, xbe->y ) ) {
|
||||||
*( state->selected_line ) = 0;
|
*( state->selected_line ) = 0;
|
||||||
state->retv = MENU_QUICK_SWITCH | ( i & MENU_LOWER_MASK );
|
state->retv = MENU_QUICK_SWITCH | ( i & MENU_LOWER_MASK );
|
||||||
state->quit = TRUE;
|
state->quit = TRUE;
|
||||||
|
@ -666,7 +697,7 @@ static void menu_mouse_navigation ( MenuState *state, XButtonEvent *xbe )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for ( unsigned int i = 0; i < state->max_elements; i++ ) {
|
for ( unsigned int i = 0; i < state->max_elements; i++ ) {
|
||||||
if ( ( xbe->window ) == ( state->boxes[i]->window ) ) {
|
if ( intersect ( state->boxes[i], xbe->x, xbe->y ) ) {
|
||||||
// Only allow items that are visible to be selected.
|
// Only allow items that are visible to be selected.
|
||||||
if ( ( state->last_offset + i ) >= state->filtered_lines ) {
|
if ( ( state->last_offset + i ) >= state->filtered_lines ) {
|
||||||
break;
|
break;
|
||||||
|
@ -734,10 +765,20 @@ static void menu_refilter ( MenuState *state )
|
||||||
state->rchanged = TRUE;
|
state->rchanged = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void menu_draw ( MenuState *state )
|
static void menu_draw ( MenuState *state, cairo_t *draw )
|
||||||
{
|
{
|
||||||
unsigned int i, offset = 0;
|
unsigned int i, offset = 0;
|
||||||
|
|
||||||
|
unsigned pixel = color_background ( display );
|
||||||
|
|
||||||
|
cairo_set_source_rgba ( draw,
|
||||||
|
( ( pixel & 0x00FF0000 ) >> 16 ) / 256.0,
|
||||||
|
( ( pixel & 0x0000FF00 ) >> 8 ) / 256.0,
|
||||||
|
( ( pixel & 0x000000FF ) >> 0 ) / 256.0,
|
||||||
|
( ( pixel & 0xFF000000 ) >> 24 ) / 256.0
|
||||||
|
);
|
||||||
|
cairo_paint ( draw );
|
||||||
|
|
||||||
// selected row is always visible.
|
// selected row is always visible.
|
||||||
// If selected is visible do not scroll.
|
// If selected is visible do not scroll.
|
||||||
if ( ( ( state->selected - ( state->last_offset ) ) < ( state->max_elements ) ) && ( state->selected >= ( state->last_offset ) ) ) {
|
if ( ( ( state->selected - ( state->last_offset ) ) < ( state->max_elements ) ) && ( state->selected >= ( state->last_offset ) ) ) {
|
||||||
|
@ -752,7 +793,7 @@ static void menu_draw ( MenuState *state )
|
||||||
state->cur_page = page;
|
state->cur_page = page;
|
||||||
state->rchanged = TRUE;
|
state->rchanged = TRUE;
|
||||||
}
|
}
|
||||||
// Set the position.
|
// Set the position
|
||||||
scrollbar_set_handle ( state->scrollbar, page * state->max_elements );
|
scrollbar_set_handle ( state->scrollbar, page * state->max_elements );
|
||||||
}
|
}
|
||||||
// Re calculate the boxes and sizes, see if we can move this in the menu_calc*rowscolumns
|
// Re calculate the boxes and sizes, see if we can move this in the menu_calc*rowscolumns
|
||||||
|
@ -765,7 +806,7 @@ static void menu_draw ( MenuState *state )
|
||||||
|
|
||||||
// Update the handle length.
|
// Update the handle length.
|
||||||
scrollbar_set_handle_length ( state->scrollbar, columns * state->max_rows );
|
scrollbar_set_handle_length ( state->scrollbar, columns * state->max_rows );
|
||||||
scrollbar_draw ( state->scrollbar );
|
scrollbar_draw ( state->scrollbar, draw );
|
||||||
// Element width.
|
// Element width.
|
||||||
unsigned int element_width = state->w - ( 2 * ( config.padding ) );
|
unsigned int element_width = state->w - ( 2 * ( config.padding ) );
|
||||||
if ( state->scrollbar != NULL ) {
|
if ( state->scrollbar != NULL ) {
|
||||||
|
@ -781,10 +822,6 @@ static void menu_draw ( MenuState *state )
|
||||||
// Calculate number of visible rows.
|
// Calculate number of visible rows.
|
||||||
unsigned int max_elements = MIN ( a_lines, state->max_rows * columns );
|
unsigned int max_elements = MIN ( a_lines, state->max_rows * columns );
|
||||||
|
|
||||||
// Hide now invisible boxes.
|
|
||||||
for ( i = max_elements; i < state->max_elements; i++ ) {
|
|
||||||
textbox_hide ( state->boxes[i] );
|
|
||||||
}
|
|
||||||
if ( state->rchanged ) {
|
if ( state->rchanged ) {
|
||||||
// Move, resize visible boxes and show them.
|
// Move, resize visible boxes and show them.
|
||||||
for ( i = 0; i < max_elements; i++ ) {
|
for ( i = 0; i < max_elements; i++ ) {
|
||||||
|
@ -800,8 +837,7 @@ static void menu_draw ( MenuState *state )
|
||||||
textbox_font ( state->boxes[i], tbft );
|
textbox_font ( state->boxes[i], tbft );
|
||||||
textbox_text ( state->boxes[i], text );
|
textbox_text ( state->boxes[i], text );
|
||||||
}
|
}
|
||||||
textbox_show ( state->boxes[i] );
|
textbox_draw ( state->boxes[i], draw );
|
||||||
textbox_draw ( state->boxes[i] );
|
|
||||||
}
|
}
|
||||||
state->rchanged = FALSE;
|
state->rchanged = FALSE;
|
||||||
}
|
}
|
||||||
|
@ -813,37 +849,63 @@ static void menu_draw ( MenuState *state )
|
||||||
state->sw->mgrv ( state->line_map[i + offset], state->sw, &fstate );
|
state->sw->mgrv ( state->line_map[i + offset], state->sw, &fstate );
|
||||||
TextBoxFontType tbft = fstate | ( ( i + offset ) == state->selected ? HIGHLIGHT : type );
|
TextBoxFontType tbft = fstate | ( ( i + offset ) == state->selected ? HIGHLIGHT : type );
|
||||||
textbox_font ( state->boxes[i], tbft );
|
textbox_font ( state->boxes[i], tbft );
|
||||||
textbox_draw ( state->boxes[i] );
|
textbox_draw ( state->boxes[i], draw );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
cairo_show_page ( draw );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void menu_update ( MenuState *state )
|
static void menu_update ( MenuState *state )
|
||||||
{
|
{
|
||||||
textbox_draw ( state->case_indicator );
|
cairo_surface_t *surf = cairo_image_surface_create ( CAIRO_FORMAT_ARGB32, state->w, state->h );
|
||||||
textbox_draw ( state->prompt_tb );
|
cairo_t *d = cairo_create ( surf );
|
||||||
textbox_draw ( state->text );
|
cairo_set_operator ( d, CAIRO_OPERATOR_SOURCE );
|
||||||
|
|
||||||
|
menu_draw ( state, d );
|
||||||
|
textbox_draw ( state->prompt_tb, d );
|
||||||
|
textbox_draw ( state->text, d );
|
||||||
|
textbox_draw ( state->case_indicator, d );
|
||||||
if ( state->message_tb ) {
|
if ( state->message_tb ) {
|
||||||
textbox_draw ( state->message_tb );
|
textbox_draw ( state->message_tb, d );
|
||||||
}
|
}
|
||||||
menu_draw ( state );
|
unsigned pixel = color_separator ( display );
|
||||||
// Why do we need the special -1?
|
|
||||||
XDrawLine ( display, main_window, gc, 0, state->line_height + ( config.padding ) * 1 + config.line_margin + 1, state->w,
|
cairo_set_source_rgba ( d,
|
||||||
state->line_height + ( config.padding ) * 1 + config.line_margin + 1 );
|
( ( pixel & 0x00FF0000 ) >> 16 ) / 256.0,
|
||||||
|
( ( pixel & 0x0000FF00 ) >> 8 ) / 256.0,
|
||||||
|
( ( pixel & 0x000000FF ) >> 0 ) / 256.0,
|
||||||
|
( ( pixel & 0xFF000000 ) >> 24 ) / 256.0
|
||||||
|
);
|
||||||
|
if ( strcmp ( config.separator_style, "dash" ) == 0 ) {
|
||||||
|
const double dashes[1] = { 4 };
|
||||||
|
cairo_set_dash ( d, dashes, 1, 0.0 );
|
||||||
|
}
|
||||||
|
cairo_move_to ( d, 0, state->line_height + ( config.padding ) * 1 + config.line_margin + 1 );
|
||||||
|
cairo_line_to ( d, state->w, state->line_height + ( config.padding ) * 1 + config.line_margin + 1 );
|
||||||
|
cairo_stroke ( d );
|
||||||
if ( state->message_tb ) {
|
if ( state->message_tb ) {
|
||||||
XDrawLine ( display, main_window, gc, 0, state->top_offset - ( config.line_margin ) - 1,
|
cairo_move_to ( d, 0, state->top_offset - ( config.line_margin ) - 1 );
|
||||||
state->w, state->top_offset - ( config.line_margin ) - 1 );
|
cairo_line_to ( d, state->w, state->top_offset - ( config.line_margin ) - 1 );
|
||||||
|
cairo_stroke ( d );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( config.sidebar_mode == TRUE ) {
|
if ( config.sidebar_mode == TRUE ) {
|
||||||
XDrawLine ( display, main_window, gc, 0, state->h - state->line_height - ( config.padding ) * 1 - 1 - config.line_margin,
|
cairo_move_to ( d, 0, state->h - state->line_height - ( config.padding ) * 1 - 1 - config.line_margin );
|
||||||
state->w, state->h - state->line_height - ( config.padding ) * 1 - 1 - config.line_margin );
|
cairo_line_to ( d, state->w, state->h - state->line_height - ( config.padding ) * 1 - 1 - config.line_margin );
|
||||||
|
cairo_stroke ( d );
|
||||||
|
|
||||||
for ( unsigned int j = 0; j < num_switchers; j++ ) {
|
for ( unsigned int j = 0; j < num_switchers; j++ ) {
|
||||||
textbox_draw ( switchers[j].tb );
|
textbox_draw ( switchers[j].tb, d );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
state->update = FALSE;
|
state->update = FALSE;
|
||||||
|
|
||||||
|
cairo_set_source_surface ( draw, surf, 0, 0 );
|
||||||
|
cairo_paint ( draw );
|
||||||
|
|
||||||
|
cairo_destroy ( d );
|
||||||
|
cairo_surface_destroy ( surf );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -883,8 +945,7 @@ static void menu_resize ( MenuState *state )
|
||||||
for ( unsigned int j = 0; j < num_switchers; j++ ) {
|
for ( unsigned int j = 0; j < num_switchers; j++ ) {
|
||||||
textbox_moveresize ( switchers[j].tb, config.padding + j * ( width + config.line_margin ),
|
textbox_moveresize ( switchers[j].tb, config.padding + j * ( width + config.line_margin ),
|
||||||
state->h - state->line_height - config.padding, width, state->line_height );
|
state->h - state->line_height - config.padding, width, state->line_height );
|
||||||
textbox_show ( switchers[j].tb );
|
textbox_draw ( switchers[j].tb, draw );
|
||||||
textbox_draw ( switchers[j].tb );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
@ -915,7 +976,7 @@ static void menu_resize ( MenuState *state )
|
||||||
}
|
}
|
||||||
// Add newly added boxes.
|
// Add newly added boxes.
|
||||||
for ( unsigned int i = last_length; i < state->max_elements; i++ ) {
|
for ( unsigned int i = last_length; i < state->max_elements; i++ ) {
|
||||||
state->boxes[i] = textbox_create ( main_window, &vinfo, map, rstate, x_offset, y_offset,
|
state->boxes[i] = textbox_create ( rstate, x_offset, y_offset,
|
||||||
state->element_width, element_height, NORMAL, "" );
|
state->element_width, element_height, NORMAL, "" );
|
||||||
}
|
}
|
||||||
scrollbar_resize ( state->scrollbar, -1, ( state->max_rows ) * ( element_height ) - config.line_margin );
|
scrollbar_resize ( state->scrollbar, -1, ( state->max_rows ) * ( element_height ) - config.line_margin );
|
||||||
|
@ -977,7 +1038,7 @@ MenuReturn menu ( Switcher *sw, char **input, char *prompt, unsigned int *select
|
||||||
|
|
||||||
// we need this at this point so we can get height.
|
// we need this at this point so we can get height.
|
||||||
state.line_height = textbox_get_estimated_char_height ();
|
state.line_height = textbox_get_estimated_char_height ();
|
||||||
state.case_indicator = textbox_create ( main_window, &vinfo, map, TB_AUTOWIDTH, ( config.padding ), ( config.padding ),
|
state.case_indicator = textbox_create ( TB_AUTOWIDTH, ( config.padding ), ( config.padding ),
|
||||||
0, state.line_height, NORMAL, "*" );
|
0, state.line_height, NORMAL, "*" );
|
||||||
// Height of a row.
|
// Height of a row.
|
||||||
if ( config.menu_lines == 0 ) {
|
if ( config.menu_lines == 0 ) {
|
||||||
|
@ -993,13 +1054,13 @@ MenuReturn menu ( Switcher *sw, char **input, char *prompt, unsigned int *select
|
||||||
menu_calculate_window_and_element_width ( &state, &mon );
|
menu_calculate_window_and_element_width ( &state, &mon );
|
||||||
|
|
||||||
// Prompt box.
|
// Prompt box.
|
||||||
state.prompt_tb = textbox_create ( main_window, &vinfo, map, TB_AUTOWIDTH, ( config.padding ), ( config.padding ),
|
state.prompt_tb = textbox_create ( TB_AUTOWIDTH, ( config.padding ), ( config.padding ),
|
||||||
0, state.line_height, NORMAL, prompt );
|
0, state.line_height, NORMAL, prompt );
|
||||||
// Entry box
|
// Entry box
|
||||||
int entrybox_width = state.w - ( 2 * ( config.padding ) ) - textbox_get_width ( state.prompt_tb )
|
int entrybox_width = state.w - ( 2 * ( config.padding ) ) - textbox_get_width ( state.prompt_tb )
|
||||||
- textbox_get_width ( state.case_indicator );
|
- textbox_get_width ( state.case_indicator );
|
||||||
|
|
||||||
state.text = textbox_create ( main_window, &vinfo, map, TB_EDITABLE,
|
state.text = textbox_create ( TB_EDITABLE,
|
||||||
( config.padding ) + textbox_get_width ( state.prompt_tb ), ( config.padding ),
|
( config.padding ) + textbox_get_width ( state.prompt_tb ), ( config.padding ),
|
||||||
entrybox_width, state.line_height, NORMAL, *input );
|
entrybox_width, state.line_height, NORMAL, *input );
|
||||||
|
|
||||||
|
@ -1008,19 +1069,17 @@ MenuReturn menu ( Switcher *sw, char **input, char *prompt, unsigned int *select
|
||||||
// Move indicator to end.
|
// Move indicator to end.
|
||||||
textbox_move ( state.case_indicator, config.padding + textbox_get_width ( state.prompt_tb ) + entrybox_width, config.padding );
|
textbox_move ( state.case_indicator, config.padding + textbox_get_width ( state.prompt_tb ) + entrybox_width, config.padding );
|
||||||
|
|
||||||
textbox_show ( state.text );
|
|
||||||
textbox_show ( state.prompt_tb );
|
|
||||||
|
|
||||||
if ( config.case_sensitive ) {
|
if ( config.case_sensitive ) {
|
||||||
textbox_show ( state.case_indicator );
|
textbox_text ( state.case_indicator, "*" );
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
textbox_text ( state.case_indicator, "" );
|
||||||
}
|
}
|
||||||
|
|
||||||
state.message_tb = NULL;
|
state.message_tb = NULL;
|
||||||
if ( message ) {
|
if ( message ) {
|
||||||
state.message_tb = textbox_create ( main_window, &vinfo, map, TB_AUTOHEIGHT | TB_MARKUP | TB_WRAP,
|
state.message_tb = textbox_create ( TB_AUTOHEIGHT | TB_MARKUP | TB_WRAP,
|
||||||
( config.padding ), state.top_offset, state.w - ( 2 * ( config.padding ) ),
|
( config.padding ), state.top_offset, state.w - ( 2 * ( config.padding ) ),
|
||||||
-1, NORMAL, message );
|
-1, NORMAL, message );
|
||||||
textbox_show ( state.message_tb );
|
|
||||||
state.top_offset += textbox_get_height ( state.message_tb );
|
state.top_offset += textbox_get_height ( state.message_tb );
|
||||||
state.top_offset += config.line_margin * 2 + 2;
|
state.top_offset += config.line_margin * 2 + 2;
|
||||||
}
|
}
|
||||||
|
@ -1037,12 +1096,12 @@ MenuReturn menu ( Switcher *sw, char **input, char *prompt, unsigned int *select
|
||||||
rstate = TB_MARKUP;
|
rstate = TB_MARKUP;
|
||||||
}
|
}
|
||||||
for ( unsigned int i = 0; i < state.max_elements; i++ ) {
|
for ( unsigned int i = 0; i < state.max_elements; i++ ) {
|
||||||
state.boxes[i] = textbox_create ( main_window, &vinfo, map, rstate, x_offset, y_offset,
|
state.boxes[i] = textbox_create ( rstate, x_offset, y_offset,
|
||||||
state.element_width, element_height, NORMAL, "" );
|
state.element_width, element_height, NORMAL, "" );
|
||||||
}
|
}
|
||||||
if ( !config.hide_scrollbar ) {
|
if ( !config.hide_scrollbar ) {
|
||||||
unsigned int sbw = config.line_margin + 8;
|
unsigned int sbw = config.line_margin + 8;
|
||||||
state.scrollbar = scrollbar_create ( main_window, &vinfo, map, state.w - config.padding - sbw, state.top_offset,
|
state.scrollbar = scrollbar_create ( state.w - config.padding - sbw, state.top_offset,
|
||||||
sbw, ( state.max_rows - 1 ) * ( element_height + config.line_margin ) + element_height );
|
sbw, ( state.max_rows - 1 ) * ( element_height + config.line_margin ) + element_height );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1074,22 +1133,22 @@ MenuReturn menu ( Switcher *sw, char **input, char *prompt, unsigned int *select
|
||||||
if ( config.sidebar_mode == TRUE ) {
|
if ( config.sidebar_mode == TRUE ) {
|
||||||
int width = ( state.w - ( 2 * ( config.padding ) + ( num_switchers - 1 ) * config.line_margin ) ) / num_switchers;
|
int width = ( state.w - ( 2 * ( config.padding ) + ( num_switchers - 1 ) * config.line_margin ) ) / num_switchers;
|
||||||
for ( unsigned int j = 0; j < num_switchers; j++ ) {
|
for ( unsigned int j = 0; j < num_switchers; j++ ) {
|
||||||
switchers[j].tb = textbox_create ( main_window, &vinfo, map, TB_CENTER, config.padding + j * ( width + config.line_margin ),
|
switchers[j].tb = textbox_create ( TB_CENTER, config.padding + j * ( width + config.line_margin ),
|
||||||
state.h - state.line_height - config.padding, width, state.line_height,
|
state.h - state.line_height - config.padding, width, state.line_height,
|
||||||
( j == curr_switcher ) ? HIGHLIGHT : NORMAL, switchers[j].sw->name );
|
( j == curr_switcher ) ? HIGHLIGHT : NORMAL, switchers[j].sw->name );
|
||||||
textbox_show ( switchers[j].tb );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
scrollbar_show ( state.scrollbar );
|
|
||||||
// Display it.
|
// Display it.
|
||||||
XMoveResizeWindow ( display, main_window, state.x, state.y, state.w, state.h );
|
XMoveResizeWindow ( display, main_window, state.x, state.y, state.w, state.h );
|
||||||
|
cairo_xlib_surface_set_size ( surface, state.w, state.h );
|
||||||
XMapRaised ( display, main_window );
|
XMapRaised ( display, main_window );
|
||||||
|
|
||||||
// if grabbing keyboard failed, fall through
|
// if grabbing keyboard failed, fall through
|
||||||
state.selected = 0;
|
state.selected = 0;
|
||||||
|
|
||||||
state.quit = FALSE;
|
state.quit = FALSE;
|
||||||
|
state.update = TRUE;
|
||||||
menu_refilter ( &state );
|
menu_refilter ( &state );
|
||||||
|
|
||||||
for ( unsigned int i = 0; ( *( state.selected_line ) ) < UINT32_MAX && !state.selected && i < state.filtered_lines; i++ ) {
|
for ( unsigned int i = 0; ( *( state.selected_line ) ) < UINT32_MAX && !state.selected && i < state.filtered_lines; i++ ) {
|
||||||
|
@ -1151,6 +1210,7 @@ MenuReturn menu ( Switcher *sw, char **input, char *prompt, unsigned int *select
|
||||||
if ( state.w != (unsigned int) xce.width || state.h != (unsigned int ) xce.height ) {
|
if ( state.w != (unsigned int) xce.width || state.h != (unsigned int ) xce.height ) {
|
||||||
state.w = xce.width;
|
state.w = xce.width;
|
||||||
state.h = xce.height;
|
state.h = xce.height;
|
||||||
|
cairo_xlib_surface_set_size ( surface, state.w, state.h );
|
||||||
menu_resize ( &state );
|
menu_resize ( &state );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1173,8 +1233,10 @@ MenuReturn menu ( Switcher *sw, char **input, char *prompt, unsigned int *select
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
XMotionEvent xme = ev.xmotion;
|
XMotionEvent xme = ev.xmotion;
|
||||||
state.selected = scrollbar_clicked ( state.scrollbar, xme.y );
|
if ( xme.x >= state.scrollbar->x && xme.x < ( state.scrollbar->x + state.scrollbar->w ) ) {
|
||||||
state.update = TRUE;
|
state.selected = scrollbar_clicked ( state.scrollbar, xme.y );
|
||||||
|
state.update = TRUE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Button press event.
|
// Button press event.
|
||||||
else if ( ev.type == ButtonPress ) {
|
else if ( ev.type == ButtonPress ) {
|
||||||
|
@ -1222,10 +1284,10 @@ MenuReturn menu ( Switcher *sw, char **input, char *prompt, unsigned int *select
|
||||||
state.refilter = TRUE;
|
state.refilter = TRUE;
|
||||||
state.update = TRUE;
|
state.update = TRUE;
|
||||||
if ( config.case_sensitive ) {
|
if ( config.case_sensitive ) {
|
||||||
textbox_show ( state.case_indicator );
|
textbox_text ( state.case_indicator, "*" );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
textbox_hide ( state.case_indicator );
|
textbox_text ( state.case_indicator, "" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Special delete entry command.
|
// Special delete entry command.
|
||||||
|
@ -1253,7 +1315,7 @@ MenuReturn menu ( Switcher *sw, char **input, char *prompt, unsigned int *select
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rc = textbox_keypress ( state.text, &ev );
|
int rc = textbox_keypress ( state.text, xic, &ev );
|
||||||
// Row is accepted.
|
// Row is accepted.
|
||||||
if ( rc < 0 ) {
|
if ( rc < 0 ) {
|
||||||
shift = ( ( ev.xkey.state & ShiftMask ) == ShiftMask );
|
shift = ( ( ev.xkey.state & ShiftMask ) == ShiftMask );
|
||||||
|
@ -1370,10 +1432,9 @@ void error_dialog ( const char *msg, int markup )
|
||||||
menu_calculate_window_and_element_width ( &state, &mon );
|
menu_calculate_window_and_element_width ( &state, &mon );
|
||||||
state.max_elements = 0;
|
state.max_elements = 0;
|
||||||
|
|
||||||
state.text = textbox_create ( main_window, &vinfo, map, TB_AUTOHEIGHT|TB_WRAP + ( ( markup ) ? TB_MARKUP : 0 ),
|
state.text = textbox_create ( TB_AUTOHEIGHT | TB_WRAP + ( ( markup ) ? TB_MARKUP : 0 ),
|
||||||
( config.padding ), ( config.padding ),
|
( config.padding ), ( config.padding ),
|
||||||
( state.w - ( 2 * ( config.padding ) ) ), 1, NORMAL, ( msg != NULL ) ? msg : "" );
|
( state.w - ( 2 * ( config.padding ) ) ), 1, NORMAL, ( msg != NULL ) ? msg : "" );
|
||||||
textbox_show ( state.text );
|
|
||||||
state.line_height = textbox_get_height ( state.text );
|
state.line_height = textbox_get_height ( state.text );
|
||||||
|
|
||||||
// resize window vertically to suit
|
// resize window vertically to suit
|
||||||
|
@ -1382,7 +1443,7 @@ void error_dialog ( const char *msg, int markup )
|
||||||
// Move the window to the correct x,y position.
|
// Move the window to the correct x,y position.
|
||||||
calculate_window_position ( &state, &mon );
|
calculate_window_position ( &state, &mon );
|
||||||
XMoveResizeWindow ( display, main_window, state.x, state.y, state.w, state.h );
|
XMoveResizeWindow ( display, main_window, state.x, state.y, state.w, state.h );
|
||||||
|
cairo_xlib_surface_set_size ( surface, state.w, state.h );
|
||||||
// Display it.
|
// Display it.
|
||||||
XMapRaised ( display, main_window );
|
XMapRaised ( display, main_window );
|
||||||
|
|
||||||
|
@ -1392,7 +1453,7 @@ void error_dialog ( const char *msg, int markup )
|
||||||
while ( !state.quit ) {
|
while ( !state.quit ) {
|
||||||
// Update if requested.
|
// Update if requested.
|
||||||
if ( state.update ) {
|
if ( state.update ) {
|
||||||
textbox_draw ( state.text );
|
textbox_draw ( state.text, draw );
|
||||||
state.update = FALSE;
|
state.update = FALSE;
|
||||||
}
|
}
|
||||||
// Wait for event.
|
// Wait for event.
|
||||||
|
@ -1430,7 +1491,7 @@ static int setup ()
|
||||||
if ( pfd >= 0 ) {
|
if ( pfd >= 0 ) {
|
||||||
// Request truecolor visual.
|
// Request truecolor visual.
|
||||||
create_visual_and_colormap ( display );
|
create_visual_and_colormap ( display );
|
||||||
textbox_setup ( &vinfo, map );
|
textbox_setup ( );
|
||||||
}
|
}
|
||||||
return pfd;
|
return pfd;
|
||||||
}
|
}
|
||||||
|
@ -1448,11 +1509,18 @@ static void teardown ( int pfd )
|
||||||
XUnmapWindow ( display, main_window );
|
XUnmapWindow ( display, main_window );
|
||||||
XDestroyWindow ( display, main_window );
|
XDestroyWindow ( display, main_window );
|
||||||
main_window = None;
|
main_window = None;
|
||||||
|
XDestroyIC ( xic );
|
||||||
|
XCloseIM ( xim );
|
||||||
}
|
}
|
||||||
if ( gc != NULL ) {
|
if ( draw ) {
|
||||||
XFreeGC ( display, gc );
|
cairo_destroy ( draw );
|
||||||
gc = NULL;
|
draw = NULL;
|
||||||
}
|
}
|
||||||
|
if ( surface ) {
|
||||||
|
cairo_surface_destroy ( surface );
|
||||||
|
surface = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if ( map != None ) {
|
if ( map != None ) {
|
||||||
XFreeColormap ( display, map );
|
XFreeColormap ( display, map );
|
||||||
map = None;
|
map = None;
|
||||||
|
@ -1580,11 +1648,10 @@ static void cleanup ()
|
||||||
release_keyboard ( display );
|
release_keyboard ( display );
|
||||||
XDestroyWindow ( display, main_window );
|
XDestroyWindow ( display, main_window );
|
||||||
main_window = None;
|
main_window = None;
|
||||||
|
XDestroyIC ( xic );
|
||||||
|
XCloseIM ( xim );
|
||||||
}
|
}
|
||||||
if ( gc != NULL ) {
|
|
||||||
XFreeGC ( display, gc );
|
|
||||||
gc = NULL;
|
|
||||||
}
|
|
||||||
if ( sncontext != NULL ) {
|
if ( sncontext != NULL ) {
|
||||||
sn_launchee_context_unref ( sncontext );
|
sn_launchee_context_unref ( sncontext );
|
||||||
sncontext = NULL;
|
sncontext = NULL;
|
||||||
|
|
|
@ -37,53 +37,26 @@
|
||||||
|
|
||||||
extern Display *display;
|
extern Display *display;
|
||||||
|
|
||||||
scrollbar *scrollbar_create ( Window parent, XVisualInfo *vinfo, Colormap map, short x, short y, short w, short h )
|
scrollbar *scrollbar_create ( short x, short y, short w, short h )
|
||||||
{
|
{
|
||||||
scrollbar *sb = g_malloc0 ( sizeof ( scrollbar ) );
|
scrollbar *sb = g_malloc0 ( sizeof ( scrollbar ) );
|
||||||
|
|
||||||
sb->parent = parent;
|
sb->x = x;
|
||||||
sb->x = x;
|
sb->y = y;
|
||||||
sb->y = y;
|
sb->w = MAX ( 1, w );
|
||||||
sb->w = MAX ( 1, w );
|
sb->h = MAX ( 1, h );
|
||||||
sb->h = MAX ( 1, h );
|
|
||||||
|
|
||||||
sb->length = 10;
|
sb->length = 10;
|
||||||
sb->pos = 0;
|
sb->pos = 0;
|
||||||
sb->pos_length = 4;
|
sb->pos_length = 4;
|
||||||
|
|
||||||
XSetWindowAttributes attr;
|
|
||||||
attr.colormap = map;
|
|
||||||
attr.border_pixel = color_border ( display );
|
|
||||||
attr.background_pixel = color_background ( display );
|
|
||||||
sb->window = XCreateWindow ( display, sb->parent, sb->x, sb->y, sb->w, sb->h, 0, vinfo->depth, InputOutput, vinfo->visual,
|
|
||||||
CWColormap | CWBorderPixel | CWBackPixel, &attr );
|
|
||||||
|
|
||||||
XSelectInput ( display, sb->window, ExposureMask | ButtonPressMask | Button1MotionMask );
|
|
||||||
sb->gc = XCreateGC ( display, sb->window, 0, 0 );
|
|
||||||
XSetForeground ( display, sb->gc, color_separator ( display ) );
|
|
||||||
|
|
||||||
// Create GC.
|
// Create GC.
|
||||||
return sb;
|
return sb;
|
||||||
}
|
}
|
||||||
|
|
||||||
void scrollbar_show ( scrollbar *sb )
|
|
||||||
{
|
|
||||||
if ( sb != NULL ) {
|
|
||||||
XMapWindow ( display, sb->window );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void scrollbar_hide ( scrollbar *sb )
|
|
||||||
{
|
|
||||||
if ( sb != NULL ) {
|
|
||||||
XUnmapWindow ( display, sb->window );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void scrollbar_free ( scrollbar *sb )
|
void scrollbar_free ( scrollbar *sb )
|
||||||
{
|
{
|
||||||
if ( sb != NULL ) {
|
if ( sb != NULL ) {
|
||||||
XFreeGC ( display, sb->gc );
|
|
||||||
XDestroyWindow ( display, sb->window );
|
|
||||||
g_free ( sb );
|
g_free ( sb );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -109,7 +82,7 @@ void scrollbar_set_handle_length ( scrollbar *sb, unsigned int pos_length )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void scrollbar_draw ( scrollbar *sb )
|
void scrollbar_draw ( scrollbar *sb, cairo_t *draw )
|
||||||
{
|
{
|
||||||
if ( sb != NULL ) {
|
if ( sb != NULL ) {
|
||||||
// Calculate position and size.
|
// Calculate position and size.
|
||||||
|
@ -124,9 +97,16 @@ void scrollbar_draw ( scrollbar *sb )
|
||||||
// Cap length;
|
// Cap length;
|
||||||
height = MIN ( bh - y + 1, ( height ) );
|
height = MIN ( bh - y + 1, ( height ) );
|
||||||
// Redraw base window
|
// Redraw base window
|
||||||
XClearWindow ( display, sb->window );
|
unsigned pixel = color_separator ( display );
|
||||||
// Paint the handle.
|
|
||||||
XFillRectangle ( display, sb->window, sb->gc, config.line_margin, y, sb->w - config.line_margin, height );
|
cairo_set_source_rgba ( draw,
|
||||||
|
( ( pixel & 0x00FF0000 ) >> 16 ) / 256.0,
|
||||||
|
( ( pixel & 0x0000FF00 ) >> 8 ) / 256.0,
|
||||||
|
( ( pixel & 0x000000FF ) >> 0 ) / 256.0,
|
||||||
|
( ( pixel & 0xFF000000 ) >> 24 ) / 256.0
|
||||||
|
);
|
||||||
|
cairo_rectangle ( draw, sb->x + config.line_margin, sb->y + y, sb->w - config.line_margin, height );
|
||||||
|
cairo_fill ( draw );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void scrollbar_resize ( scrollbar *sb, int w, int h )
|
void scrollbar_resize ( scrollbar *sb, int w, int h )
|
||||||
|
@ -138,7 +118,6 @@ void scrollbar_resize ( scrollbar *sb, int w, int h )
|
||||||
if ( w > 0 ) {
|
if ( w > 0 ) {
|
||||||
sb->w = w;
|
sb->w = w;
|
||||||
}
|
}
|
||||||
XResizeWindow ( display, sb->window, sb->w, sb->h );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void scrollbar_move ( scrollbar *sb, int x, int y )
|
void scrollbar_move ( scrollbar *sb, int x, int y )
|
||||||
|
@ -146,18 +125,20 @@ void scrollbar_move ( scrollbar *sb, int x, int y )
|
||||||
if ( sb != NULL ) {
|
if ( sb != NULL ) {
|
||||||
sb->x = x;
|
sb->x = x;
|
||||||
sb->y = y;
|
sb->y = y;
|
||||||
XMoveWindow ( display, sb->window, x, y );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int scrollbar_clicked ( scrollbar *sb, int y )
|
unsigned int scrollbar_clicked ( scrollbar *sb, int y )
|
||||||
{
|
{
|
||||||
if ( sb != NULL ) {
|
if ( sb != NULL ) {
|
||||||
y = MIN ( MAX ( 1, y ), sb->h - 1 ) - 1;
|
if ( y >= sb->y && y < ( sb->y + sb->h ) ) {
|
||||||
const short bh = sb->h - 2;
|
y -= sb->y;
|
||||||
float sec = ( ( bh ) / (float) sb->length );
|
y = MIN ( MAX ( 1, y ), sb->h - 1 ) - 1;
|
||||||
unsigned int sel = y / sec;
|
const short bh = sb->h - 2;
|
||||||
return MIN ( sel, sb->length - 1 );
|
float sec = ( ( bh ) / (float) sb->length );
|
||||||
|
unsigned int sel = y / sec;
|
||||||
|
return MIN ( sel, sb->length - 1 );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
358
source/textbox.c
358
source/textbox.c
|
@ -32,9 +32,8 @@
|
||||||
#include <X11/Xproto.h>
|
#include <X11/Xproto.h>
|
||||||
#include <X11/keysym.h>
|
#include <X11/keysym.h>
|
||||||
#include <X11/XKBlib.h>
|
#include <X11/XKBlib.h>
|
||||||
#include <X11/Xft/Xft.h>
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <pango/pangocairo.h>
|
||||||
#include "rofi.h"
|
#include "rofi.h"
|
||||||
#include "textbox.h"
|
#include "textbox.h"
|
||||||
#include "keyb.h"
|
#include "keyb.h"
|
||||||
|
@ -47,16 +46,13 @@ extern Display *display;
|
||||||
* Font + font color cache.
|
* Font + font color cache.
|
||||||
* Avoid re-loading font on every change on every textbox.
|
* Avoid re-loading font on every change on every textbox.
|
||||||
*/
|
*/
|
||||||
XVisualInfo *visual_info;
|
|
||||||
Colormap target_colormap;
|
|
||||||
|
|
||||||
typedef struct _RowColor
|
typedef struct _RowColor
|
||||||
{
|
{
|
||||||
XftColor fg;
|
Color fg;
|
||||||
XftColor bg;
|
Color bg;
|
||||||
XftColor bgalt;
|
Color bgalt;
|
||||||
XftColor hlfg;
|
Color hlfg;
|
||||||
XftColor hlbg;
|
Color hlbg;
|
||||||
} RowColor;
|
} RowColor;
|
||||||
|
|
||||||
#define num_states 3
|
#define num_states 3
|
||||||
|
@ -64,45 +60,23 @@ RowColor colors[num_states];
|
||||||
|
|
||||||
PangoContext *p_context = NULL;
|
PangoContext *p_context = NULL;
|
||||||
|
|
||||||
// Xft text box, optionally editable
|
textbox* textbox_create ( TextboxFlags flags, short x, short y, short w, short h,
|
||||||
textbox* textbox_create ( Window parent, XVisualInfo *vinfo, Colormap map, TextboxFlags flags, short x, short y, short w, short h,
|
|
||||||
TextBoxFontType tbft, const char *text )
|
TextBoxFontType tbft, const char *text )
|
||||||
{
|
{
|
||||||
textbox *tb = g_malloc0 ( sizeof ( textbox ) );
|
textbox *tb = g_malloc0 ( sizeof ( textbox ) );
|
||||||
|
|
||||||
tb->flags = flags;
|
tb->flags = flags;
|
||||||
tb->parent = parent;
|
|
||||||
|
|
||||||
tb->x = x;
|
tb->x = x;
|
||||||
tb->y = y;
|
tb->y = y;
|
||||||
tb->w = MAX ( 1, w );
|
tb->w = MAX ( 1, w );
|
||||||
tb->h = MAX ( 1, h );
|
tb->h = MAX ( 1, h );
|
||||||
|
|
||||||
tb->layout = pango_layout_new ( p_context );
|
|
||||||
|
|
||||||
tb->changed = FALSE;
|
tb->changed = FALSE;
|
||||||
|
|
||||||
unsigned int cp;
|
tb->main_surface = cairo_image_surface_create ( CAIRO_FORMAT_ARGB32, tb->w, tb->h );
|
||||||
switch ( tbft )
|
tb->main_draw = cairo_create ( tb->main_surface );
|
||||||
{
|
tb->layout = pango_cairo_create_layout ( tb->main_draw );
|
||||||
case HIGHLIGHT:
|
|
||||||
cp = colors[NORMAL].hlbg.pixel;
|
|
||||||
break;
|
|
||||||
case ALT:
|
|
||||||
cp = colors[NORMAL].bgalt.pixel;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
cp = colors[NORMAL].bg.pixel;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
XSetWindowAttributes attr;
|
|
||||||
attr.colormap = map;
|
|
||||||
attr.border_pixel = cp;
|
|
||||||
attr.background_pixel = cp;
|
|
||||||
tb->window = XCreateWindow ( display, tb->parent, tb->x, tb->y, tb->w, tb->h, 0, vinfo->depth,
|
|
||||||
InputOutput, vinfo->visual, CWColormap | CWBorderPixel | CWBackPixel, &attr );
|
|
||||||
|
|
||||||
PangoFontDescription *pfd = pango_font_description_from_string ( config.menu_font );
|
PangoFontDescription *pfd = pango_font_description_from_string ( config.menu_font );
|
||||||
pango_layout_set_font_description ( tb->layout, pfd );
|
pango_layout_set_font_description ( tb->layout, pfd );
|
||||||
pango_font_description_free ( pfd );
|
pango_font_description_free ( pfd );
|
||||||
|
@ -117,20 +91,9 @@ textbox* textbox_create ( Window parent, XVisualInfo *vinfo, Colormap map, Textb
|
||||||
// auto height/width modes get handled here
|
// auto height/width modes get handled here
|
||||||
textbox_moveresize ( tb, tb->x, tb->y, tb->w, tb->h );
|
textbox_moveresize ( tb, tb->x, tb->y, tb->w, tb->h );
|
||||||
|
|
||||||
// edit mode controls
|
|
||||||
if ( tb->flags & TB_EDITABLE ) {
|
|
||||||
tb->xim = XOpenIM ( display, NULL, NULL, NULL );
|
|
||||||
tb->xic = XCreateIC ( tb->xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNClientWindow,
|
|
||||||
tb->window, XNFocusWindow, tb->window, NULL );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
XSelectInput ( display, tb->window, ButtonPressMask );
|
|
||||||
}
|
|
||||||
|
|
||||||
return tb;
|
return tb;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set an Xft font by name
|
|
||||||
void textbox_font ( textbox *tb, TextBoxFontType tbft )
|
void textbox_font ( textbox *tb, TextBoxFontType tbft )
|
||||||
{
|
{
|
||||||
RowColor *color = &( colors[tbft & STATE_MASK] );
|
RowColor *color = &( colors[tbft & STATE_MASK] );
|
||||||
|
@ -149,14 +112,19 @@ void textbox_font ( textbox *tb, TextBoxFontType tbft )
|
||||||
tb->color_fg = color->fg;
|
tb->color_fg = color->fg;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if ( tb->tbft != tbft ) {
|
||||||
|
tb->update = TRUE;
|
||||||
|
}
|
||||||
tb->tbft = tbft;
|
tb->tbft = tbft;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set the default text to display
|
// set the default text to display
|
||||||
void textbox_text ( textbox *tb, const char *text )
|
void textbox_text ( textbox *tb, const char *text )
|
||||||
{
|
{
|
||||||
|
tb->update = TRUE;
|
||||||
g_free ( tb->text );
|
g_free ( tb->text );
|
||||||
const gchar *last_pointer = NULL;
|
const gchar *last_pointer = NULL;
|
||||||
|
|
||||||
if ( g_utf8_validate ( text, -1, &last_pointer ) ) {
|
if ( g_utf8_validate ( text, -1, &last_pointer ) ) {
|
||||||
tb->text = g_strdup ( text );
|
tb->text = g_strdup ( text );
|
||||||
}
|
}
|
||||||
|
@ -169,6 +137,7 @@ void textbox_text ( textbox *tb, const char *text )
|
||||||
tb->text = g_strdup ( "Invalid UTF-8 string." );
|
tb->text = g_strdup ( "Invalid UTF-8 string." );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( tb->flags & TB_MARKUP ) {
|
if ( tb->flags & TB_MARKUP ) {
|
||||||
pango_layout_set_markup ( tb->layout, tb->text, strlen ( tb->text ) );
|
pango_layout_set_markup ( tb->layout, tb->text, strlen ( tb->text ) );
|
||||||
}
|
}
|
||||||
|
@ -187,7 +156,6 @@ void textbox_move ( textbox *tb, int x, int y )
|
||||||
if ( x != tb->x || y != tb->y ) {
|
if ( x != tb->x || y != tb->y ) {
|
||||||
tb->x = x;
|
tb->x = x;
|
||||||
tb->y = y;
|
tb->y = y;
|
||||||
XMoveResizeWindow ( display, tb->window, tb->x, tb->y, tb->w, tb->h );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// within the parent handled auto width/height modes
|
// within the parent handled auto width/height modes
|
||||||
|
@ -195,12 +163,7 @@ void textbox_moveresize ( textbox *tb, int x, int y, int w, int h )
|
||||||
{
|
{
|
||||||
if ( tb->flags & TB_AUTOWIDTH ) {
|
if ( tb->flags & TB_AUTOWIDTH ) {
|
||||||
pango_layout_set_width ( tb->layout, -1 );
|
pango_layout_set_width ( tb->layout, -1 );
|
||||||
if ( w > 1 ) {
|
w = textbox_get_width ( tb );
|
||||||
w = MIN ( w, textbox_get_width ( tb ) );
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
w = textbox_get_width ( tb );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// set ellipsize
|
// set ellipsize
|
||||||
|
@ -224,106 +187,123 @@ void textbox_moveresize ( textbox *tb, int x, int y, int w, int h )
|
||||||
tb->y = y;
|
tb->y = y;
|
||||||
tb->h = MAX ( 1, h );
|
tb->h = MAX ( 1, h );
|
||||||
tb->w = MAX ( 1, w );
|
tb->w = MAX ( 1, w );
|
||||||
XMoveResizeWindow ( display, tb->window, tb->x, tb->y, tb->w, tb->h );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We always want to update this
|
// We always want to update this
|
||||||
pango_layout_set_width ( tb->layout, PANGO_SCALE * ( tb->w - 2 * SIDE_MARGIN ) );
|
pango_layout_set_width ( tb->layout, PANGO_SCALE * ( tb->w - 2 * SIDE_MARGIN ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
void textbox_show ( textbox *tb )
|
|
||||||
{
|
|
||||||
XMapWindow ( display, tb->window );
|
|
||||||
}
|
|
||||||
void textbox_hide ( textbox *tb )
|
|
||||||
{
|
|
||||||
XUnmapWindow ( display, tb->window );
|
|
||||||
}
|
|
||||||
|
|
||||||
// will also unmap the window if still displayed
|
// will also unmap the window if still displayed
|
||||||
void textbox_free ( textbox *tb )
|
void textbox_free ( textbox *tb )
|
||||||
{
|
{
|
||||||
if ( tb == NULL ) {
|
if ( tb == NULL ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ( tb->flags & TB_EDITABLE ) {
|
|
||||||
XDestroyIC ( tb->xic );
|
|
||||||
XCloseIM ( tb->xim );
|
|
||||||
}
|
|
||||||
|
|
||||||
g_free ( tb->text );
|
g_free ( tb->text );
|
||||||
|
|
||||||
if ( tb->layout != NULL ) {
|
if ( tb->layout != NULL ) {
|
||||||
g_object_unref ( tb->layout );
|
g_object_unref ( tb->layout );
|
||||||
}
|
}
|
||||||
|
if ( tb->main_draw ) {
|
||||||
|
cairo_destroy ( tb->main_draw );
|
||||||
|
tb->main_draw = NULL;
|
||||||
|
}
|
||||||
|
if ( tb->main_surface ) {
|
||||||
|
cairo_surface_destroy ( tb->main_surface );
|
||||||
|
tb->main_surface = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
XDestroyWindow ( display, tb->window );
|
|
||||||
g_free ( tb );
|
g_free ( tb );
|
||||||
}
|
}
|
||||||
|
|
||||||
void textbox_draw ( textbox *tb )
|
static void texbox_update ( textbox *tb )
|
||||||
{
|
{
|
||||||
GC context = XCreateGC ( display, tb->window, 0, 0 );
|
if ( tb->update ) {
|
||||||
Pixmap canvas = XCreatePixmap ( display, tb->window, tb->w, tb->h, visual_info->depth );
|
if ( tb->main_surface ) {
|
||||||
XftDraw *draw = XftDrawCreate ( display, canvas, visual_info->visual, target_colormap );
|
cairo_destroy ( tb->main_draw );
|
||||||
|
cairo_surface_destroy ( tb->main_surface );
|
||||||
// clear canvas
|
tb->main_draw = NULL;
|
||||||
XftDrawRect ( draw, &tb->color_bg, 0, 0, tb->w, tb->h );
|
tb->main_surface = NULL;
|
||||||
|
|
||||||
char *text = tb->text ? tb->text : "";
|
|
||||||
int text_len = strlen ( text );
|
|
||||||
int font_height = textbox_get_font_height ( tb );
|
|
||||||
|
|
||||||
int cursor_x = 0;
|
|
||||||
int cursor_width = MAX ( 2, font_height / 10 );
|
|
||||||
|
|
||||||
if ( tb->changed ) {
|
|
||||||
if ( tb->flags & TB_MARKUP ) {
|
|
||||||
pango_layout_set_markup ( tb->layout, text, text_len );
|
|
||||||
}
|
}
|
||||||
else{
|
tb->main_surface = cairo_image_surface_create ( CAIRO_FORMAT_ARGB32, tb->w, tb->h );
|
||||||
pango_layout_set_text ( tb->layout, text, text_len );
|
tb->main_draw = cairo_create ( tb->main_surface );
|
||||||
|
PangoFontDescription *pfd = pango_font_description_from_string ( config.menu_font );
|
||||||
|
pango_font_description_free ( pfd );
|
||||||
|
cairo_set_operator ( tb->main_draw, CAIRO_OPERATOR_SOURCE );
|
||||||
|
|
||||||
|
pango_cairo_update_layout ( tb->main_draw, tb->layout );
|
||||||
|
char *text = tb->text ? tb->text : "";
|
||||||
|
int text_len = strlen ( text );
|
||||||
|
int font_height = textbox_get_font_height ( tb );
|
||||||
|
|
||||||
|
int cursor_x = 0;
|
||||||
|
int cursor_width = MAX ( 2, font_height / 10 );
|
||||||
|
|
||||||
|
if ( tb->changed ) {
|
||||||
|
if ( tb->flags & TB_MARKUP ) {
|
||||||
|
pango_layout_set_markup ( tb->layout, text, text_len );
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
pango_layout_set_text ( tb->layout, text, text_len );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( tb->flags & TB_EDITABLE ) {
|
||||||
|
PangoRectangle pos;
|
||||||
|
int cursor_offset = 0;
|
||||||
|
cursor_offset = MIN ( tb->cursor, text_len );
|
||||||
|
pango_layout_get_cursor_pos ( tb->layout, cursor_offset, &pos, NULL );
|
||||||
|
// Add a small 4px offset between cursor and last glyph.
|
||||||
|
cursor_x = pos.x / PANGO_SCALE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip the side MARGIN on the X axis.
|
||||||
|
int x = SIDE_MARGIN;
|
||||||
|
int y = 0;
|
||||||
|
|
||||||
|
if ( tb->flags & TB_RIGHT ) {
|
||||||
|
int line_width = 0;
|
||||||
|
// Get actual width.
|
||||||
|
pango_layout_get_pixel_size ( tb->layout, &line_width, NULL );
|
||||||
|
x = ( tb->w - line_width - SIDE_MARGIN );
|
||||||
|
}
|
||||||
|
else if ( tb->flags & TB_CENTER ) {
|
||||||
|
int tw = textbox_get_font_width ( tb );
|
||||||
|
x = ( ( tb->w - tw - 2 * SIDE_MARGIN ) ) / 2;
|
||||||
|
}
|
||||||
|
y = ( ( tb->h - textbox_get_font_height ( tb ) ) ) / 2;
|
||||||
|
|
||||||
|
// Set ARGB
|
||||||
|
Color col = tb->color_bg;
|
||||||
|
cairo_set_source_rgba ( tb->main_draw, col.red, col.green, col.blue, col.alpha );
|
||||||
|
cairo_paint ( tb->main_draw );
|
||||||
|
|
||||||
|
// Set ARGB
|
||||||
|
col = tb->color_fg;
|
||||||
|
cairo_set_source_rgba ( tb->main_draw, col.red, col.green, col.blue, col.alpha );
|
||||||
|
cairo_move_to ( tb->main_draw, x, y );
|
||||||
|
pango_cairo_show_layout ( tb->main_draw, tb->layout );
|
||||||
|
|
||||||
|
//cairo_fill(tb->draw);
|
||||||
|
// draw the cursor
|
||||||
|
if ( tb->flags & TB_EDITABLE ) {
|
||||||
|
cairo_rectangle ( tb->main_draw, x + cursor_x, y, cursor_width, font_height );
|
||||||
|
cairo_fill ( tb->main_draw );
|
||||||
|
}
|
||||||
|
|
||||||
|
tb->update = FALSE;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
void textbox_draw ( textbox *tb, cairo_t *draw )
|
||||||
|
{
|
||||||
|
texbox_update ( tb );
|
||||||
|
|
||||||
if ( tb->flags & TB_EDITABLE ) {
|
/* Write buffer */
|
||||||
PangoRectangle pos;
|
|
||||||
int cursor_offset = 0;
|
|
||||||
cursor_offset = MIN ( tb->cursor, text_len );
|
|
||||||
pango_layout_get_cursor_pos ( tb->layout, cursor_offset, &pos, NULL );
|
|
||||||
// Add a small 4px offset between cursor and last glyph.
|
|
||||||
cursor_x = pos.x / PANGO_SCALE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip the side MARGIN on the X axis.
|
cairo_set_source_surface ( draw, tb->main_surface, tb->x, tb->y );
|
||||||
int x = PANGO_SCALE * SIDE_MARGIN;
|
cairo_rectangle ( draw, tb->x, tb->y, tb->w, tb->h );
|
||||||
int y = 0;
|
cairo_fill ( draw );
|
||||||
|
|
||||||
if ( tb->flags & TB_RIGHT ) {
|
|
||||||
int line_width = 0;
|
|
||||||
// Get actual width.
|
|
||||||
pango_layout_get_pixel_size ( tb->layout, &line_width, NULL );
|
|
||||||
x = ( tb->w - line_width - SIDE_MARGIN ) * PANGO_SCALE;
|
|
||||||
}
|
|
||||||
else if ( tb->flags & TB_CENTER ) {
|
|
||||||
int tw = textbox_get_font_width ( tb );
|
|
||||||
x = ( PANGO_SCALE * ( tb->w - tw - 2 * SIDE_MARGIN ) ) / 2;
|
|
||||||
}
|
|
||||||
y = ( PANGO_SCALE * ( tb->h - textbox_get_font_height ( tb ) ) ) / 2;
|
|
||||||
// Render the layout.
|
|
||||||
pango_xft_render_layout ( draw, &( tb->color_fg ), tb->layout, x, y );
|
|
||||||
|
|
||||||
// draw the cursor
|
|
||||||
if ( tb->flags & TB_EDITABLE ) {
|
|
||||||
XftDrawRect ( draw, &tb->color_fg, x / PANGO_SCALE + cursor_x, y / PANGO_SCALE, cursor_width, font_height );
|
|
||||||
}
|
|
||||||
|
|
||||||
// flip canvas to window
|
|
||||||
// XClearWindow ( display, tb->window);
|
|
||||||
XCopyArea ( display, canvas, tb->window, context, 0, 0, tb->w, tb->h, 0, 0 );
|
|
||||||
|
|
||||||
XFreeGC ( display, context );
|
|
||||||
XftDrawDestroy ( draw );
|
|
||||||
XFreePixmap ( display, canvas );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// cursor handling for edit mode
|
// cursor handling for edit mode
|
||||||
|
@ -331,6 +311,7 @@ void textbox_cursor ( textbox *tb, int pos )
|
||||||
{
|
{
|
||||||
int length = ( tb->text == NULL ) ? 0 : strlen ( tb->text );
|
int length = ( tb->text == NULL ) ? 0 : strlen ( tb->text );
|
||||||
tb->cursor = MAX ( 0, MIN ( length, pos ) );
|
tb->cursor = MAX ( 0, MIN ( length, pos ) );
|
||||||
|
tb->update = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// move right
|
// move right
|
||||||
|
@ -413,6 +394,7 @@ static void textbox_cursor_dec_word ( textbox *tb )
|
||||||
void textbox_cursor_end ( textbox *tb )
|
void textbox_cursor_end ( textbox *tb )
|
||||||
{
|
{
|
||||||
tb->cursor = ( int ) strlen ( tb->text );
|
tb->cursor = ( int ) strlen ( tb->text );
|
||||||
|
tb->update = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// insert text
|
// insert text
|
||||||
|
@ -430,6 +412,7 @@ void textbox_insert ( textbox *tb, int pos, char *str )
|
||||||
|
|
||||||
// Set modified, lay out need te be redrawn
|
// Set modified, lay out need te be redrawn
|
||||||
tb->changed = TRUE;
|
tb->changed = TRUE;
|
||||||
|
tb->update = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove text
|
// remove text
|
||||||
|
@ -449,6 +432,7 @@ void textbox_delete ( textbox *tb, int pos, int dlen )
|
||||||
}
|
}
|
||||||
// Set modified, lay out need te be redrawn
|
// Set modified, lay out need te be redrawn
|
||||||
tb->changed = TRUE;
|
tb->changed = TRUE;
|
||||||
|
tb->update = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete on character
|
// delete on character
|
||||||
|
@ -495,24 +479,18 @@ static void textbox_cursor_del_word ( textbox *tb )
|
||||||
// 0 = unhandled
|
// 0 = unhandled
|
||||||
// 1 = handled
|
// 1 = handled
|
||||||
// -1 = handled and return pressed (finished)
|
// -1 = handled and return pressed (finished)
|
||||||
int textbox_keypress ( textbox *tb, XEvent *ev )
|
int textbox_keypress ( textbox *tb, XIC xic, XEvent *ev )
|
||||||
{
|
{
|
||||||
KeySym key;
|
KeySym key;
|
||||||
Status stat;
|
Status stat;
|
||||||
char pad[32];
|
char pad[32];
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
// This is needed for letting the Input Method handle combined keys.
|
|
||||||
// E.g. `e into è
|
|
||||||
if ( XFilterEvent ( ev, tb->window ) ) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !( tb->flags & TB_EDITABLE ) ) {
|
if ( !( tb->flags & TB_EDITABLE ) ) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
len = Xutf8LookupString ( tb->xic, &ev->xkey, pad, sizeof ( pad ), &key, &stat );
|
len = Xutf8LookupString ( xic, &ev->xkey, pad, sizeof ( pad ), &key, &stat );
|
||||||
pad[len] = 0;
|
pad[len] = 0;
|
||||||
// Left or Ctrl-b
|
// Left or Ctrl-b
|
||||||
if ( abe_test_action ( MOVE_CHAR_BACK, ev->xkey.state, key ) ) {
|
if ( abe_test_action ( MOVE_CHAR_BACK, ev->xkey.state, key ) ) {
|
||||||
|
@ -590,41 +568,27 @@ int textbox_keypress ( textbox *tb, XEvent *ev )
|
||||||
/***
|
/***
|
||||||
* Font setup.
|
* Font setup.
|
||||||
*/
|
*/
|
||||||
static void parse_color ( Visual *visual, Colormap colormap,
|
static void parse_color ( char *bg, Color *col )
|
||||||
const char *bg, XftColor *color, const char *def )
|
|
||||||
{
|
{
|
||||||
if ( bg == NULL ) {
|
if ( bg == NULL ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ( strncmp ( bg, "argb:", 5 ) == 0 ) {
|
if ( strncmp ( bg, "argb:", 5 ) == 0 ) {
|
||||||
XRenderColor col;
|
|
||||||
unsigned int val = strtoul ( &bg[5], NULL, 16 );
|
unsigned int val = strtoul ( &bg[5], NULL, 16 );
|
||||||
col.alpha = ( ( val & 0xFF000000 ) >> 24 ) * 255;
|
col->alpha = ( ( val & 0xFF000000 ) >> 24 ) / 256.0;
|
||||||
col.red = ( ( val & 0x00FF0000 ) >> 16 ) * 255;
|
col->red = ( ( val & 0x00FF0000 ) >> 16 ) / 256.0;
|
||||||
col.green = ( ( val & 0x0000FF00 ) >> 8 ) * 255;
|
col->green = ( ( val & 0x0000FF00 ) >> 8 ) / 256.0;
|
||||||
col.blue = ( ( val & 0x000000FF ) ) * 255;
|
col->blue = ( ( val & 0x000000FF ) ) / 256.0;
|
||||||
if ( !XftColorAllocValue ( display, visual, colormap, &col, color ) ) {
|
|
||||||
fprintf ( stderr, "Failed to parse color: '%s'\n", bg );
|
|
||||||
// Go for default.
|
|
||||||
if ( !XftColorAllocName ( display, visual, colormap, def, color ) ) {
|
|
||||||
fprintf ( stderr, "Cannot allocate default color, giving up.\n" );
|
|
||||||
exit ( EXIT_FAILURE );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if ( !XftColorAllocName ( display, visual, colormap, bg, color ) ) {
|
unsigned int val = strtoul ( &bg[1], NULL, 16 );
|
||||||
fprintf ( stderr, "Failed to parse color: '%s'\n", bg );
|
col->alpha = 1;
|
||||||
// Go for default.
|
col->red = ( ( val & 0x00FF0000 ) >> 16 ) / 256.0;
|
||||||
if ( !XftColorAllocName ( display, visual, colormap, def, color ) ) {
|
col->green = ( ( val & 0x0000FF00 ) >> 8 ) / 256.0;
|
||||||
fprintf ( stderr, "Cannot allocate default color, giving up.\n" );
|
col->blue = ( ( val & 0x000000FF ) ) / 256.0;
|
||||||
exit ( EXIT_FAILURE );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static void textbox_parse_string ( XVisualInfo *visual, Colormap colormap, const char *str,
|
static void textbox_parse_string ( const char *str, RowColor *color )
|
||||||
RowColor *color )
|
|
||||||
{
|
{
|
||||||
if ( str == NULL ) {
|
if ( str == NULL ) {
|
||||||
return;
|
return;
|
||||||
|
@ -637,79 +601,61 @@ static void textbox_parse_string ( XVisualInfo *visual, Colormap colormap, const
|
||||||
switch ( index )
|
switch ( index )
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
parse_color ( visual->visual, colormap, g_strstrip ( token ), &( color->bg ), "black" );
|
parse_color ( g_strstrip ( token ), &( color->bg ) );
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
parse_color ( visual->visual, colormap, g_strstrip ( token ), &( color->fg ), "white" );
|
parse_color ( g_strstrip ( token ), &( color->fg ) );
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
parse_color ( visual->visual, colormap, g_strstrip ( token ), &( color->bgalt ), "black" );
|
parse_color ( g_strstrip ( token ), &( color->bgalt ) );
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
parse_color ( visual->visual, colormap, g_strstrip ( token ), &( color->hlbg ), "black" );
|
parse_color ( g_strstrip ( token ), &( color->hlbg ) );
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
parse_color ( visual->visual, colormap, g_strstrip ( token ), &( color->hlfg ), "white" );
|
parse_color ( g_strstrip ( token ), &( color->hlfg ) );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
g_free ( cstr );
|
g_free ( cstr );
|
||||||
}
|
}
|
||||||
void textbox_setup ( XVisualInfo *visual, Colormap colormap )
|
void textbox_setup ( void )
|
||||||
{
|
{
|
||||||
visual_info = visual;
|
|
||||||
target_colormap = colormap;
|
|
||||||
|
|
||||||
if ( config.color_enabled ) {
|
if ( config.color_enabled ) {
|
||||||
textbox_parse_string ( visual, target_colormap, config.color_normal, &( colors[NORMAL] ) );
|
textbox_parse_string ( config.color_normal, &( colors[NORMAL] ) );
|
||||||
textbox_parse_string ( visual, target_colormap, config.color_urgent, &( colors[URGENT] ) );
|
textbox_parse_string ( config.color_urgent, &( colors[URGENT] ) );
|
||||||
textbox_parse_string ( visual, target_colormap, config.color_active, &( colors[ACTIVE] ) );
|
textbox_parse_string ( config.color_active, &( colors[ACTIVE] ) );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
parse_color ( visual_info->visual, target_colormap, config.menu_bg, &( colors[NORMAL].bg ), "black" );
|
parse_color ( config.menu_bg, &( colors[NORMAL].bg ) );
|
||||||
parse_color ( visual_info->visual, target_colormap, config.menu_fg, &( colors[NORMAL].fg ), "white" );
|
parse_color ( config.menu_fg, &( colors[NORMAL].fg ) );
|
||||||
parse_color ( visual_info->visual, target_colormap, config.menu_bg_alt, &( colors[NORMAL].bgalt ), "black" );
|
parse_color ( config.menu_bg_alt, &( colors[NORMAL].bgalt ) );
|
||||||
parse_color ( visual_info->visual, target_colormap, config.menu_hlfg, &( colors[NORMAL].hlfg ), "white" );
|
parse_color ( config.menu_hlfg, &( colors[NORMAL].hlfg ) );
|
||||||
parse_color ( visual_info->visual, target_colormap, config.menu_hlbg, &( colors[NORMAL].hlbg ), "black" );
|
parse_color ( config.menu_hlbg, &( colors[NORMAL].hlbg ) );
|
||||||
|
|
||||||
parse_color ( visual_info->visual, target_colormap, config.menu_bg_urgent, &( colors[URGENT].bg ), "black" );
|
parse_color ( config.menu_bg_urgent, &( colors[URGENT].bg ) );
|
||||||
parse_color ( visual_info->visual, target_colormap, config.menu_fg_urgent, &( colors[URGENT].fg ), "white" );
|
parse_color ( config.menu_fg_urgent, &( colors[URGENT].fg ) );
|
||||||
parse_color ( visual_info->visual, target_colormap, config.menu_bg_alt, &( colors[URGENT].bgalt ), "black" );
|
parse_color ( config.menu_bg_alt, &( colors[URGENT].bgalt ) );
|
||||||
parse_color ( visual_info->visual, target_colormap, config.menu_hlfg_urgent, &( colors[URGENT].hlfg ), "white" );
|
parse_color ( config.menu_hlfg_urgent, &( colors[URGENT].hlfg ) );
|
||||||
parse_color ( visual_info->visual, target_colormap, config.menu_hlbg_urgent, &( colors[URGENT].hlbg ), "black" );
|
parse_color ( config.menu_hlbg_urgent, &( colors[URGENT].hlbg ) );
|
||||||
|
|
||||||
parse_color ( visual_info->visual, target_colormap, config.menu_bg_active, &( colors[ACTIVE].bg ), "black" );
|
parse_color ( config.menu_bg_active, &( colors[ACTIVE].bg ) );
|
||||||
parse_color ( visual_info->visual, target_colormap, config.menu_fg_active, &( colors[ACTIVE].fg ), "white" );
|
parse_color ( config.menu_fg_active, &( colors[ACTIVE].fg ) );
|
||||||
parse_color ( visual_info->visual, target_colormap, config.menu_bg_alt, &( colors[ACTIVE].bgalt ), "black" );
|
parse_color ( config.menu_bg_alt, &( colors[ACTIVE].bgalt ) );
|
||||||
parse_color ( visual_info->visual, target_colormap, config.menu_hlfg_active, &( colors[ACTIVE].hlfg ), "white" );
|
parse_color ( config.menu_hlfg_active, &( colors[ACTIVE].hlfg ) );
|
||||||
parse_color ( visual_info->visual, target_colormap, config.menu_hlbg_active, &( colors[ACTIVE].hlbg ), "black" );
|
parse_color ( config.menu_hlbg_active, &( colors[ACTIVE].hlbg ) );
|
||||||
}
|
}
|
||||||
PangoFontMap *font_map = pango_xft_get_font_map ( display, DefaultScreen ( display ) );
|
PangoFontMap *font_map = pango_cairo_font_map_new ();
|
||||||
p_context = pango_font_map_create_context ( font_map );
|
p_context = pango_font_map_create_context ( font_map );
|
||||||
}
|
g_object_unref ( font_map );
|
||||||
|
|
||||||
static void textbox_clean_rowcolor ( RowColor * color )
|
|
||||||
{
|
|
||||||
XftColorFree ( display, visual_info->visual, target_colormap, &( color->fg ) );
|
|
||||||
XftColorFree ( display, visual_info->visual, target_colormap, &( color->bg ) );
|
|
||||||
XftColorFree ( display, visual_info->visual, target_colormap, &( color->bgalt ) );
|
|
||||||
XftColorFree ( display, visual_info->visual, target_colormap, &( color->hlfg ) );
|
|
||||||
XftColorFree ( display, visual_info->visual, target_colormap, &( color->hlbg ) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void textbox_cleanup ( void )
|
void textbox_cleanup ( void )
|
||||||
{
|
{
|
||||||
if ( p_context ) {
|
if ( p_context ) {
|
||||||
for ( unsigned int st = 0; st < num_states; st++ ) {
|
|
||||||
textbox_clean_rowcolor ( &colors[st] );
|
|
||||||
}
|
|
||||||
|
|
||||||
g_object_unref ( p_context );
|
g_object_unref ( p_context );
|
||||||
pango_xft_shutdown_display ( display, DefaultScreen ( display ) );
|
p_context = NULL;
|
||||||
p_context = NULL;
|
|
||||||
visual_info = NULL;
|
|
||||||
target_colormap = None;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -83,11 +83,16 @@ int main ( G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv )
|
||||||
0, 0, 200, 100, config.menu_bw, vinfo.depth, InputOutput,
|
0, 0, 200, 100, config.menu_bw, vinfo.depth, InputOutput,
|
||||||
vinfo.visual, CWColormap | CWBorderPixel | CWBackPixel, &attr );
|
vinfo.visual, CWColormap | CWBorderPixel | CWBackPixel, &attr );
|
||||||
TASSERT ( mw != None );
|
TASSERT ( mw != None );
|
||||||
|
|
||||||
|
cairo_surface_t *surface = cairo_xlib_surface_create ( display, mw, vinfo.visual, 200, 100 );
|
||||||
|
// Create a drawable.
|
||||||
|
cairo_t *draw = cairo_create ( surface );
|
||||||
|
cairo_set_operator ( draw, CAIRO_OPERATOR_SOURCE );
|
||||||
// Set alternate row to normal row.
|
// Set alternate row to normal row.
|
||||||
config.menu_bg_alt = config.menu_bg;
|
config.menu_bg_alt = config.menu_bg;
|
||||||
textbox_setup ( &vinfo, map );
|
textbox_setup ( );
|
||||||
textbox *box =
|
textbox *box =
|
||||||
textbox_create ( mw, &vinfo, map, TB_EDITABLE | TB_AUTOWIDTH | TB_AUTOHEIGHT, 0, 0, -1, -1,
|
textbox_create ( TB_EDITABLE | TB_AUTOWIDTH | TB_AUTOHEIGHT, 0, 0, -1, -1,
|
||||||
NORMAL,
|
NORMAL,
|
||||||
"test" );
|
"test" );
|
||||||
TASSERT ( box != NULL );
|
TASSERT ( box != NULL );
|
||||||
|
@ -158,19 +163,19 @@ int main ( G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv )
|
||||||
TASSERT ( box->cursor == 5 );
|
TASSERT ( box->cursor == 5 );
|
||||||
|
|
||||||
textbox_font ( box, HIGHLIGHT );
|
textbox_font ( box, HIGHLIGHT );
|
||||||
textbox_draw ( box );
|
textbox_draw ( box, draw );
|
||||||
|
|
||||||
textbox_show ( box );
|
|
||||||
textbox_move ( box, 12, 13 );
|
textbox_move ( box, 12, 13 );
|
||||||
TASSERT ( box->x == 12 );
|
TASSERT ( box->x == 12 );
|
||||||
TASSERT ( box->y == 13 );
|
TASSERT ( box->y == 13 );
|
||||||
textbox_hide ( box );
|
|
||||||
|
|
||||||
textbox_free ( box );
|
textbox_free ( box );
|
||||||
textbox_cleanup ( );
|
textbox_cleanup ( );
|
||||||
|
|
||||||
cleanup_abe ();
|
cleanup_abe ();
|
||||||
|
|
||||||
|
cairo_destroy ( draw );
|
||||||
|
cairo_surface_destroy ( surface );
|
||||||
XDestroyWindow ( display, mw );
|
XDestroyWindow ( display, mw );
|
||||||
XCloseDisplay ( display );
|
XCloseDisplay ( display );
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue