e16-epplets/api/epplet.c

5882 lines
132 KiB
C

#include "config.h"
#include "epplet.h"
#include <errno.h>
#include <fcntl.h>
#include <sys/resource.h>
#include <sys/utsname.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <X11/Xatom.h>
#include <X11/XKBlib.h>
#include <X11/keysym.h>
#include <X11/extensions/shape.h>
#define DEPTH() DefaultDepth(disp, DefaultScreen(disp))
#define DEBUG_EVENTS 0
#define SET_HINTS_EWM 1
#define CRSR_WDTH 2
typedef struct {
Window win;
int w;
int h;
char win_vert;
Pixmap bg_pmap;
Pixmap bg_mask;
Pixmap bg_bg;
} EppWindow;
typedef EppWindow *Epplet_window;
EAPI Display *disp = NULL;
static int window_num = 0; /* For window list */
static Epplet_window *windows = NULL; /* List of windows to loop though */
static Epplet_window context_win; /* Current context win */
static int window_stack_pos = 0; /* For context changes */
static Epplet_window *window_stack; /* For context changes */
static Epplet_window mainwin; /* Always the main epplet window */
static Atom wmDeleteWindow;
static Display *dd = NULL;
static Window comms_win = 0;
static Window my_win = 0;
static Window root = 0;
static ETimer *q_first = NULL;
static XContext xid_context = 0;
static char *conf_dir = NULL;
static char *data_dir = NULL;
static char *e16_user_dir = NULL;
static char *epplet_name = NULL;
static char *epplet_cfg_file = NULL;
static int epplet_instance = 0;
static char epplet_visible = 0;
static int gad_num = 0;
static Epplet_gadget *gads = NULL;
static Epplet_gadget last_gadget = NULL;
static void *expose_data = NULL;
static void *moveresize_data = NULL;
static void *buttonpress_data = NULL;
static void *buttonrelease_data = NULL;
static void *mousemotion_data = NULL;
static void *keypress_data = NULL;
static void *keyrelease_data = NULL;
static void *enter_data = NULL;
static void *leave_data = NULL;
static void *focusin_data = NULL;
static void *focusout_data = NULL;
static void *delete_data = NULL;
static void *event_data = NULL;
static void *comms_data = NULL;
static void *child_data = NULL;
static void (*expose_func)(void *data, Window win, int x, int y, int w,
int h) = NULL;
static void (*moveresize_func)(void *data, Window win, int x, int y,
int w, int h) = NULL;
static void (*buttonpress_func)(void *data, Window win, int x, int y,
int b) = NULL;
static void (*buttonrelease_func)(void *data, Window win, int x, int y,
int b) = NULL;
static void (*mousemotion_func)(void *data, Window win, int x, int y) =
NULL;
static void (*keypress_func)(void *data, Window win, char *key) = NULL;
static void (*keyrelease_func)(void *data, Window win, char *key) =
NULL;
static void (*enter_func)(void *data, Window win) = NULL;
static void (*leave_func)(void *data, Window win) = NULL;
static void (*focusin_func)(void *data, Window win) = NULL;
static void (*focusout_func)(void *data, Window win) = NULL;
static int (*delete_func)(void *data, Window win) = NULL;
static void (*event_func)(void *data, XEvent * ev) = NULL;
static void (*comms_func)(void *data, const char *s) = NULL;
static void (*child_func)(void *data, int pid, int exit_code) = NULL;
/* For Keeping a list of windows owned by the epplet, to loop through and
* do stuff with. */
static void Epplet_register_window(Epplet_window win);
static void Epplet_unregister_window(Epplet_window win);
static void Epplet_window_destroy_children(Epplet_window win);
static Epplet_window Epplet_window_get_from_Window(Window win);
static Window Epplet_internal_create_window(int w, int h,
const char *title,
char vertical, char decorate);
static void remember_stuff(void *data);
#define MWM_HINTS_DECORATIONS (1L << 1)
typedef struct {
unsigned long flags;
unsigned long functions;
unsigned long decorations;
long inputMode;
unsigned long status;
} MWMHints;
struct _etimer {
char *name;
void (*func)(void *data);
void *data;
double in;
char just_added;
ETimer *next;
};
#define ESYNC Epplet_send_ipc("nop");free(ECommsWaitForMessage());
/* The structures for the config file management ... */
typedef struct {
ConfigItem *entries;
int num_entries;
} ConfigDict;
static ConfigDict *config_dict = NULL;
static void CommsSetup(void);
static void CommsFindCommsWindow(void);
static void CommsHandleDestroy(Window win);
static int CommsHandlePropertyNotify(XEvent * ev);
static char *ECommsGet(XEvent * ev);
static char *ECommsWaitForMessage(void);
static void Epplet_handle_timer(void);
static ETimer *Epplet_get_first(void);
static void Epplet_handle_event(XEvent * ev);
static Bool ev_check(Display * d, XEvent * ev, XPointer p);
static const char *win_name = NULL;
static const char *win_version = NULL;
static const char *win_info = NULL;
static void Epplet_event(Epplet_gadget gadget, XEvent * ev);
static void Epplet_add_gad(Epplet_gadget gadget);
static void Epplet_del_gad(Epplet_gadget gadget);
static void Epplet_draw_button(Epplet_gadget eg);
static void Epplet_draw_textbox(Epplet_gadget eg);
static void Epplet_draw_togglebutton(Epplet_gadget eg);
static void Epplet_draw_drawingarea(Epplet_gadget eg);
static void Epplet_draw_hslider(Epplet_gadget eg);
static void Epplet_draw_vslider(Epplet_gadget eg);
static void Epplet_draw_hbar(Epplet_gadget eg);
static void Epplet_draw_vbar(Epplet_gadget eg);
static void Epplet_draw_image(Epplet_gadget eg, char un_only);
static void Epplet_draw_label(Epplet_gadget eg, char un_only);
static void Epplet_draw_popup(Epplet_gadget gadget);
static void Epplet_draw_popupbutton(Epplet_gadget eg);
static void Epplet_popup_arrange_contents(Epplet_gadget gadget);
static void Epplet_prune_events(XEvent * ev, int num);
static void Epplet_handle_child(int num);
static void Epplet_textbox_handle_keyevent(XEvent * ev,
Epplet_gadget g);
static void Epplet_refresh_backgrounds(void);
static void Epplet_textbox_textsize(Epplet_gadget gadget, int *w,
int *h, const char *s);
int Epplet_textbox_spacesize(Epplet_gadget gadget);
static void Epplet_find_instance(const char *name);
typedef struct {
GadType type;
char visible;
Epplet_window parent;
} GadGeneral;
#define GADGET_GET_TYPE(gad) (((GadGeneral *) (gad))->type)
#ifdef __GNUC__
#define GADGET_CONFIRM_TYPE(gad, type) \
do { \
if (GADGET_GET_TYPE(gad) != (type)) { \
fprintf(stderr, "ALERT: %s() called with invalid gadget " \
"type for %s (should be %s)!\n", __FUNCTION__, \
#gad, #type); \
return; \
} \
} while (0)
#define GADGET_CONFIRM_TYPE_RVAL(gad, type, rval) \
do { \
if (GADGET_GET_TYPE(gad) != (type)) { \
fprintf(stderr, "ALERT: %s() called with invalid gadget " \
"type for %s (should be %s)!\n", __FUNCTION__, \
#gad, #type); \
return (rval); \
} \
} while (0)
#else
#define GADGET_CONFIRM_TYPE(gad, type) do { \
if (GADGET_GET_TYPE(gad) != (type)) return;} while (0)
#define GADGET_CONFIRM_TYPE_RVAL(gad, type, rval) do { \
if (GADGET_GET_TYPE(gad) != (type)) return (rval);} while (0)
#endif
typedef struct {
GadGeneral general;
int x, y, w, h;
Window win;
char *label;
char *image;
char hilited;
char clicked;
char pop;
Epplet_gadget pop_parent;
char *std;
void (*func)(void *data);
void *data;
Pixmap pmap, mask;
} GadButton;
typedef struct {
GadGeneral general;
int x, y, w, h;
Window win;
int x_offset;
unsigned int cursor_pos, to_cursor;
char *image;
char *contents;
char hilited;
char size;
void (*func)(void *data);
void *data;
Pixmap pmap, mask;
} GadTextBox;
typedef struct {
GadGeneral general;
int x, y, w, h;
Window win;
char *label;
char *image;
char hilited;
char clicked;
int *val;
void (*func)(void *data);
void *data;
Pixmap pmap, mask;
} GadToggleButton;
typedef struct {
GadGeneral general;
int x, y, w, h;
Window win;
Window win_in;
} GadDrawingArea;
typedef struct {
GadGeneral general;
int x, y, w, h;
Window win;
int min, max;
int step, jump;
char hilited;
char clicked;
int *val;
void (*func)(void *data);
void *data;
Window win_knob;
} GadHSlider;
typedef struct {
GadGeneral general;
int x, y, w, h;
Window win;
int min, max;
int step, jump;
char hilited;
char clicked;
int *val;
void (*func)(void *data);
void *data;
Window win_knob;
} GadVSlider;
typedef struct {
GadGeneral general;
int x, y, w, h;
Window win;
int *val;
char dir;
Window win_in;
} GadHBar;
typedef struct {
GadGeneral general;
int x, y, w, h;
Window win;
int *val;
char dir;
Window win_in;
} GadVBar;
typedef struct {
GadGeneral general;
int x, y, w, h;
Window win;
int pw, ph;
char *image;
} GadImage;
typedef struct {
GadGeneral general;
int x, y, w, h;
Window win;
char size;
char *label;
} GadLabel;
typedef struct {
char *label;
char *image;
int w, h;
void (*func)(void *data);
void *data;
Epplet_gadget gadget;
} GadPopEntry;
typedef struct {
GadGeneral general;
int x, y, w, h;
Window win;
Epplet_gadget popbutton;
int entry_num;
GadPopEntry *entry;
char changed;
} GadPopup;
typedef struct {
GadGeneral general;
int x, y, w, h;
Window win;
char *label;
char *image;
char hilited;
char clicked;
Epplet_gadget popup;
char popped;
char *std;
Pixmap pmap, mask;
} GadPopupButton;
#if DEBUG_EVENTS
static int
HandleXError(Display * d, XErrorEvent * ev)
{
char buf[64];
XGetErrorText(disp, ev->error_code, buf, 63);
printf("*** ERROR: xid=%#lx error=%i req=%i/%i: %s\n",
ev->resourceid, ev->error_code,
ev->request_code, ev->minor_code, buf);
return 0;
}
#endif
static GC
EXCreateGC(Drawable d)
{
GC gc;
XGCValues gcv;
unsigned long mask;
gcv.graphics_exposures = False;
mask = GCGraphicsExposures;
gc = XCreateGC(disp, d, mask, &gcv);
return gc;
}
static void
EXFreeGC(GC gc)
{
XFreeGC(disp, gc);
}
char *
Epplet_wait_for_ipc(void)
{
return ECommsWaitForMessage();
}
void
Epplet_Init(const char *name, const char *version, const char *info,
int w, int h, int argc, char **argv, char vertical)
{
struct sigaction sa;
char s[1024];
XSetWindowAttributes attr;
Atom a;
XTextProperty xtp;
XClassHint *xch;
XSizeHints sh;
struct utsname ubuf;
MWMHints mwm;
char *msg;
#if SET_HINTS_EWM
Atom atom_list[8];
int atom_count;
#endif
mainwin = malloc(sizeof(EppWindow));
mainwin->win_vert = vertical;
w *= 16;
h *= 16;
disp = XOpenDisplay(NULL);
if (!disp)
{
fprintf(stderr, "Epplet Error: Cannot open display\n");
exit(1);
}
#if DEBUG_EVENTS
XSetErrorHandler(HandleXError);
#if DEBUG_EVENTS > 1
XSynchronize(disp, True);
#endif
#endif
dd = disp;
root = DefaultRootWindow(dd);
imlib_context_set_display(disp);
imlib_context_set_visual(DefaultVisual(disp, DefaultScreen(disp)));
imlib_context_set_colormap(DefaultColormap(disp, DefaultScreen(disp)));
XSelectInput(disp, DefaultRootWindow(disp), PropertyChangeMask);
/* Find the instance number for this instance and compose the name from it */
Epplet_find_instance(name);
/* create a window with everythign set */
attr.backing_store = NotUseful;
attr.override_redirect = False;
attr.colormap = imlib_context_get_colormap();
attr.border_pixel = 0;
attr.background_pixel = 0;
attr.save_under = False;
attr.event_mask = StructureNotifyMask | ButtonPressMask |
ButtonReleaseMask | PointerMotionMask | EnterWindowMask |
LeaveWindowMask | KeyPressMask | KeyReleaseMask | ButtonMotionMask |
ExposureMask | FocusChangeMask | PropertyChangeMask |
VisibilityChangeMask;
mainwin->win = XCreateWindow(disp, DefaultRootWindow(disp), 0, 0, w, h, 0,
CopyFromParent, InputOutput, CopyFromParent,
CWOverrideRedirect | CWSaveUnder |
CWBackingStore | CWColormap | CWBackPixel |
CWBorderPixel | CWEventMask, &attr);
/* set hints to be borderless */
mwm.flags = MWM_HINTS_DECORATIONS;
mwm.functions = 0;
mwm.decorations = 0;
mwm.inputMode = 0;
mwm.status = 0;
a = XInternAtom(disp, "_MOTIF_WM_HINTS", False);
XChangeProperty(disp, mainwin->win, a, a, 32, PropModeReplace,
(unsigned char *)&mwm, sizeof(MWMHints) / 4);
/* set the window title , name , class */
XStoreName(disp, mainwin->win, epplet_name);
xch = XAllocClassHint();
xch->res_name = epplet_name;
xch->res_class = (char *)"Epplet";
XSetClassHint(disp, mainwin->win, xch);
XFree(xch);
/* set the size hints */
sh.flags = PSize | PMinSize | PMaxSize;
sh.width = w;
sh.height = h;
sh.min_width = w;
sh.min_height = h;
sh.max_width = w;
sh.max_height = h;
XSetWMNormalHints(disp, mainwin->win, &sh);
/* set the command hint */
XSetCommand(disp, mainwin->win, argv, argc);
/* set the client machine name */
if (!uname(&ubuf))
{
snprintf(s, sizeof(s), "%s", ubuf.nodename);
xtp.encoding = XA_STRING;
xtp.format = 8;
xtp.value = (unsigned char *)s;
xtp.nitems = strlen((char *)(xtp.value));
XSetWMClientMachine(disp, mainwin->win, &xtp);
}
/* set the icons name property */
XSetIconName(disp, mainwin->win, epplet_name);
#if SET_HINTS_EWM
a = XInternAtom(disp, "_NET_WM_WINDOW_TYPE", False);
atom_count = 0;
atom_list[atom_count++] =
XInternAtom(disp, "_NET_WM_WINDOW_TYPE_UTILITY", False);
XChangeProperty(disp, mainwin->win, a, XA_ATOM, 32, PropModeReplace,
(unsigned char *)atom_list, atom_count);
a = XInternAtom(disp, "_NET_WM_STATE", False);
atom_count = 0;
atom_list[atom_count++] = XInternAtom(disp, "_NET_WM_STATE_STICKY", False);
atom_list[atom_count++] =
XInternAtom(disp, "_NET_WM_STATE_SKIP_TASKBAR", False);
atom_list[atom_count++] =
XInternAtom(disp, "_NET_WM_STATE_SKIP_PAGER", False);
atom_list[atom_count++] = XInternAtom(disp, "_NET_WM_STATE_BELOW", False);
XChangeProperty(disp, mainwin->win, a, XA_ATOM, 32, PropModeReplace,
(unsigned char *)atom_list, atom_count);
#endif
win_name = epplet_name;
win_version = version;
win_info = info;
xid_context = XUniqueContext();
CommsSetup();
Epplet_send_ipc("set clientname %s", win_name);
Epplet_send_ipc("set version %s", win_version);
Epplet_send_ipc("set info %s", win_info);
ESYNC;
/* Check if the epplet imageclasses are there. */
Epplet_send_ipc("imageclass EPPLET_BUTTON query");
msg = ECommsWaitForMessage();
if (!msg || strstr(msg, "not"))
{
Epplet_dialog_ok
("Epplet Error: Your theme does not contain the imageclasses needed to run epplets.");
ESYNC;
exit(1);
}
free(msg);
mainwin->w = w;
mainwin->h = h;
mainwin->bg_pmap = 0;
mainwin->bg_bg = 0;
mainwin->bg_mask = 0;
Epplet_register_window(mainwin);
Epplet_window_push_context(mainwin->win);
Epplet_background_properties(mainwin->win_vert, mainwin->win);
wmDeleteWindow = XInternAtom(disp, "WM_DELETE_WINDOW", False);
Epplet_timer(remember_stuff, NULL, 2, "REMEMBER_TIMER");
sa.sa_handler = Epplet_handle_child;
sa.sa_flags = SA_RESTART;
sigemptyset(&sa.sa_mask);
sigaction(SIGCHLD, &sa, (struct sigaction *)0);
atexit(Epplet_cleanup);
}
static Window
Epplet_internal_create_window(int w, int h, const char *title, char vertical,
char decorate)
{
XSetWindowAttributes attr;
Atom a;
XSizeHints sh;
XClassHint *xch;
MWMHints mwm;
char *msg;
Epplet_window ret;
ret = malloc(sizeof(EppWindow));
ret->win_vert = vertical;
attr.backing_store = NotUseful;
attr.override_redirect = False;
attr.colormap = imlib_context_get_colormap();
attr.border_pixel = 0;
attr.background_pixel = 0;
attr.save_under = False;
attr.event_mask = StructureNotifyMask | ButtonPressMask |
ButtonReleaseMask | PointerMotionMask | EnterWindowMask |
LeaveWindowMask | KeyPressMask | KeyReleaseMask | ButtonMotionMask |
ExposureMask | FocusChangeMask | PropertyChangeMask |
VisibilityChangeMask;
ret->win = XCreateWindow(disp, DefaultRootWindow(disp), 0, 0, w, h, 0,
CopyFromParent, InputOutput, CopyFromParent,
CWOverrideRedirect | CWSaveUnder | CWBackingStore
| CWColormap | CWBackPixel | CWBorderPixel |
CWEventMask, &attr);
XSetTransientForHint(disp, ret->win, mainwin->win);
/* set hints? */
mwm.flags = MWM_HINTS_DECORATIONS;
mwm.functions = 0;
mwm.decorations = decorate;
mwm.inputMode = 0;
mwm.status = 0;
a = XInternAtom(disp, "_MOTIF_WM_HINTS", False);
XChangeProperty(disp, ret->win, a, a, 32, PropModeReplace,
(unsigned char *)&mwm, sizeof(MWMHints) / 4);
/* set the window title , name , class */
XStoreName(disp, ret->win, title);
xch = XAllocClassHint();
xch->res_name = epplet_name;
xch->res_class = (char *)"Epplet_window";
XSetClassHint(disp, ret->win, xch);
XFree(xch);
/* set the size hints */
sh.flags = PSize | PMinSize | PMaxSize;
sh.width = w;
sh.height = h;
sh.min_width = w;
sh.min_height = h;
sh.max_width = w;
sh.max_height = h;
XSetWMNormalHints(disp, ret->win, &sh);
/* set the icons name property */
XSetIconName(disp, ret->win, epplet_name);
ESYNC;
/* Check if the epplet imageclasses are there. */
Epplet_send_ipc("imageclass EPPLET_BUTTON query");
msg = ECommsWaitForMessage();
if (!msg || strstr(msg, "not"))
{
Epplet_dialog_ok
("Epplet Error: Your theme does not contain the imageclasses needed to run epplets.");
ESYNC;
exit(1);
}
free(msg);
ret->h = h;
ret->w = w;
ret->bg_pmap = 0;
ret->bg_mask = 0;
ret->bg_bg = 0;
Epplet_register_window(ret);
Epplet_window_push_context(ret->win);
Epplet_background_properties(ret->win_vert, ret->win);
XSetWMProtocols(disp, ret->win, &wmDeleteWindow, 1);
return ret->win;
}
void
Epplet_Exit(int rc)
{
Epplet_unremember();
Esync();
exit(rc);
}
Window
Epplet_create_window(int w, int h, const char *title, char vertical)
{
return Epplet_internal_create_window(w, h, title, vertical, 1);
}
Window
Epplet_create_window_borderless(int w, int h, const char *title, char vertical)
{
return Epplet_internal_create_window(w, h, title, vertical, 0);
}
Window
Epplet_create_window_config(int w, int h, const char *title,
void (*ok_func)(void *data),
void *ok_data, void(*apply_func)(void *data),
void *apply_data,
void(*cancel_func)(void *data), void *cancel_data)
{
Window ret;
Epplet_gadget ok_btn, apply_btn, cancel_btn;
int dw;
if (w < 200)
w = 200;
if (h < 40)
h = 40;
dw = w - 60;
ret = Epplet_create_window(w, h, title, 0);
if (cancel_func)
{
Epplet_gadget_show(cancel_btn =
Epplet_create_button("Cancel", NULL, dw, h - 20, 50,
16, NULL, 0, NULL, cancel_func,
cancel_data));
dw -= 60;
}
if (apply_func)
{
Epplet_gadget_show(apply_btn =
Epplet_create_button("Apply", NULL, dw, h - 20, 50,
16, NULL, 0, NULL, apply_func,
apply_data));
dw -= 60;
}
if (ok_func)
{
Epplet_gadget_show(ok_btn =
Epplet_create_button("Ok", NULL, dw, h - 20, 50,
16, NULL, 0, NULL, ok_func,
ok_data));
}
return ret;
}
void
Epplet_window_show(Window win)
{
XEvent ev;
XMapWindow(disp, win);
/* wait for the window to map */
XMaskEvent(disp, StructureNotifyMask, &ev);
}
void
Epplet_window_hide(Window win)
{
XEvent ev;
XUnmapWindow(disp, win);
/* wait for the window to unmap */
XMaskEvent(disp, StructureNotifyMask, &ev);
}
static Epplet_gadget
Epplet_gadget_check(Epplet_gadget g)
{
int i;
for (i = 0; i < gad_num; i++)
if (gads[i] == g)
return g;
return NULL;
}
void
Epplet_window_destroy_children(Epplet_window win)
{
int i, num;
Epplet_gadget *lst, g;
if (!gads || gad_num <= 0)
return;
/* Create work copy of gadget list
* (gads is modified by Epplet_gadget_destroy) */
num = gad_num;
lst = malloc(num * sizeof(Epplet_gadget));
memcpy(lst, gads, num * sizeof(Epplet_gadget));
for (i = 0; i < num; i++)
{
/* Check - Gadget may have been removed by recursive call */
g = Epplet_gadget_check(lst[i]);
if (!g)
continue;
if (((GadGeneral *) g)->parent == win)
Epplet_gadget_destroy(g);
}
free(lst);
}
void
Epplet_window_destroy(Window newwin)
{
XEvent ev;
Epplet_window win;
win = Epplet_window_get_from_Window(newwin);
if (!win)
return;
Epplet_unregister_window(win);
Epplet_window_destroy_children(win);
if (win->bg_pmap)
XFreePixmap(disp, win->bg_pmap);
if (win->bg_bg)
XFreePixmap(disp, win->bg_bg);
if (win->bg_mask)
XFreePixmap(disp, win->bg_mask);
XDestroyWindow(disp, win->win);
/* wait for the window to be destroyed */
XMaskEvent(disp, StructureNotifyMask, &ev);
free(win);
}
static void
Epplet_register_window(Epplet_window win)
{
window_num++;
if (windows)
windows = realloc(windows, window_num * sizeof(Epplet_window));
else
windows = malloc(window_num * sizeof(Epplet_window));
windows[window_num - 1] = win;
}
static void
Epplet_unregister_window(Epplet_window win)
{
int i, j;
for (i = 0; i < window_num; i++)
{
if (windows[i] == win)
{
for (j = i; j < window_num - 1; j++)
windows[j] = windows[j + 1];
window_num--;
if (window_num > 0)
windows = realloc(windows, window_num * sizeof(Epplet_window));
else
{
free(windows);
windows = NULL;
}
}
}
}
void
Epplet_window_push_context(Window newwin)
{
Epplet_window win;
win = Epplet_window_get_from_Window(newwin);
if (!win)
return;
window_stack = realloc(window_stack,
sizeof(Epplet_window) * (window_stack_pos + 1));
if (!window_stack)
exit(1);
window_stack[window_stack_pos] = win;
window_stack_pos++;
context_win = win;
}
Window
Epplet_window_pop_context(void)
{
Epplet_window ret;
window_stack_pos--;
ret = window_stack[window_stack_pos];
window_stack = realloc(window_stack,
sizeof(Epplet_window) * (window_stack_pos));
if (!window_stack)
exit(1);
/* Window stack pos == 0 corresponds to the main epplet window */
if (window_stack_pos < 1)
return 0;
context_win = window_stack[window_stack_pos - 1];
return ret->win;
}
/* Refresh window backgrounds on theme change */
static void
Epplet_refresh_backgrounds(void)
{
/* Loop through windows and refresh them */
int i;
for (i = 0; i < window_num; i++)
{
Epplet_window_push_context(windows[i]->win);
Epplet_background_properties(windows[i]->win_vert, windows[i]->win);
Epplet_window_pop_context();
}
}
static Epplet_window
Epplet_window_get_from_Window(Window win)
{
/* Loop through windows */
int i;
for (i = 0; i < window_num; i++)
{
if (windows[i]->win == win)
return windows[i];
}
return NULL;
}
static void
Epplet_handle_delete_event(Window xwin)
{
Epplet_window win;
win = Epplet_window_get_from_Window(xwin);
if (win)
{
if ((delete_func) && ((*delete_func) (delete_data, win->win)))
Epplet_window_destroy(win->win);
else
Epplet_window_destroy(win->win);
}
}
static void
remember_stuff(void *data __UNUSED__)
{
Epplet_remember();
}
void
Epplet_cleanup(void)
{
char s[1024];
if (conf_dir)
{
/* remove lock file */
snprintf(s, sizeof(s), "%s/.lock_%i", conf_dir, epplet_instance);
if (unlink(s) < 0)
{
Epplet_dialog_ok("Unable to remove lock file %s -- %s.\n",
s, strerror(errno));
}
}
/* save config settings */
Epplet_save_config();
}
void
Epplet_adjust_priority(int nice)
{
int prio;
prio = getpriority(PRIO_PROCESS, getpid());
setpriority(PRIO_PROCESS, getpid(), prio + nice);
}
void
Epplet_show(void)
{
XEvent ev;
epplet_visible = 1;
Epplet_redraw();
XMapWindow(disp, mainwin->win);
/* wait for the window to map */
XMaskEvent(disp, StructureNotifyMask, &ev);
}
void
Epplet_remember(void)
{
Epplet_send_ipc("wop %x snap all auto", (unsigned int)mainwin->win);
}
void
Epplet_unremember(void)
{
Epplet_send_ipc("wop %x snap none", (unsigned int)mainwin->win);
ESYNC;
}
Window
Epplet_get_main_window(void)
{
return mainwin->win;
}
void
Epplet_imageclass_apply(const char *iclass, const char *state, Window ww)
{
Epplet_send_ipc("imageclass %s apply 0x%x %s", iclass,
(unsigned int)ww, state);
}
void
Epplet_imageclass_paste(const char *iclass, const char *state, Window ww,
int x, int y, int w, int h)
{
Pixmap p = 0, m = 0;
char *msg;
GC gc;
Epplet_send_ipc("imageclass %s apply_copy 0x%x %s %i %i", iclass,
(unsigned int)ww, state, w, h);
msg = ECommsWaitForMessage();
if (msg)
{
sscanf(msg, "%x %x", (unsigned int *)&p, (unsigned int *)&m);
free(msg);
gc = EXCreateGC(context_win->win);
XSetClipMask(disp, gc, m);
XSetClipOrigin(disp, gc, x, y);
XCopyArea(disp, p, context_win->win, gc, 0, 0, w, h, x, y);
Epplet_send_ipc("imageclass %s free_pixmap 0x%x", iclass,
(unsigned int)p);
EXFreeGC(gc);
}
}
void
Epplet_imageclass_get_pixmaps(const char *iclass, const char *state, Pixmap * p,
Pixmap * m, int w, int h)
{
Pixmap pp = 0, mm = 0;
char *msg;
GC gc, mgc;
Epplet_send_ipc("imageclass %s apply_copy 0x%x %s %i %i", iclass,
(unsigned int)context_win->win, state, w, h);
msg = ECommsWaitForMessage();
if (msg)
{
sscanf(msg, "%x %x", (unsigned int *)&pp, (unsigned int *)&mm);
free(msg);
if (pp)
*p = XCreatePixmap(disp, context_win->win, w, h, DEPTH());
else
*p = 0;
if (mm)
*m = XCreatePixmap(disp, context_win->win, w, h, 1);
else
*m = 0;
if (*p)
{
gc = EXCreateGC(*p);
XCopyArea(disp, pp, *p, gc, 0, 0, w, h, 0, 0);
EXFreeGC(gc);
}
if (*m)
{
mgc = EXCreateGC(*m);
XCopyArea(disp, mm, *m, mgc, 0, 0, w, h, 0, 0);
EXFreeGC(mgc);
}
Epplet_send_ipc("imageclass %s free_pixmap 0x%x", iclass,
(unsigned int)pp);
}
}
void
Epplet_textclass_draw(const char *iclass, const char *state, Window ww, int x,
int y, const char *txt)
{
Epplet_send_ipc("textclass %s apply 0x%x %i %i %s %s", iclass,
(unsigned int)ww, x, y, state, txt);
}
void
Epplet_textclass_get_size(const char *iclass, int *w, int *h, const char *txt)
{
char *msg;
Epplet_send_ipc("textclass %s query_size %s", iclass, txt);
msg = ECommsWaitForMessage();
if (msg)
{
sscanf(msg, "%i %i", w, h);
free(msg);
}
else
{
*w = 0;
*h = 0;
}
}
void
Epplet_register_expose_handler(void (*func)
(void *data, Window win, int x, int y, int w,
int h), void *data)
{
expose_data = data;
expose_func = func;
}
void
Epplet_register_move_resize_handler(void (*func)
(void *data, Window win, int x, int y,
int w, int h), void *data)
{
moveresize_data = data;
moveresize_func = func;
}
void
Epplet_register_button_press_handler(void (*func)
(void *data, Window win, int x, int y,
int b), void *data)
{
buttonpress_data = data;
buttonpress_func = func;
}
void
Epplet_register_button_release_handler(void (*func)
(void *data, Window win, int x, int y,
int b), void *data)
{
buttonrelease_data = data;
buttonrelease_func = func;
}
void
Epplet_register_key_press_handler(void (*func)
(void *data, Window win, char *key),
void *data)
{
keypress_data = data;
keypress_func = func;
}
void
Epplet_register_key_release_handler(void (*func)
(void *data, Window win, char *key),
void *data)
{
keyrelease_data = data;
keyrelease_func = func;
}
void
Epplet_register_mouse_motion_handler(void (*func)
(void *data, Window win, int x, int y),
void *data)
{
mousemotion_data = data;
mousemotion_func = func;
}
void
Epplet_register_mouse_enter_handler(void (*func)
(void *data, Window win), void *data)
{
enter_data = data;
enter_func = func;
}
void
Epplet_register_mouse_leave_handler(void (*func)
(void *data, Window win), void *data)
{
leave_data = data;
leave_func = func;
}
void
Epplet_register_focus_in_handler(void (*func)
(void *data, Window win), void *data)
{
focusin_data = data;
focusin_func = func;
}
void
Epplet_register_focus_out_handler(void (*func)
(void *data, Window win), void *data)
{
focusout_data = data;
focusout_func = func;
}
void
Epplet_register_delete_event_handler(int (*func)
(void *data, Window win), void *data)
{
delete_data = data;
delete_func = func;
}
void
Epplet_register_event_handler(void (*func)(void *data, XEvent * ev), void *data)
{
event_data = data;
event_func = func;
}
void
Epplet_register_comms_handler(void (*func)(void *data, const char *s),
void *data)
{
comms_data = data;
comms_func = func;
}
Display *
Epplet_get_display(void)
{
return disp;
}
static void
Epplet_handle_event(XEvent * ev)
{
Epplet_gadget g = NULL;
if (event_func)
(*event_func) (event_data, ev);
switch (ev->type)
{
case ClientMessage:
{
char *msg;
if (ev->xclient.format == 32
&& ev->xclient.data.l[0] == (signed)wmDeleteWindow)
Epplet_handle_delete_event(ev->xclient.window);
else
{
msg = ECommsGet(ev);
if (msg)
{
if (comms_func)
(*comms_func) (comms_data, msg);
free(msg);
}
}
}
break;
case KeyPress:
{
if (XFindContext(disp, ev->xkey.window, xid_context,
(XPointer *) & g) == XCNOENT)
g = NULL;
if (g)
Epplet_event(g, ev);
else
{
char *key;
KeySym keysym;
keysym = XkbKeycodeToKeysym(disp, ev->xkey.keycode, 0, 0);
key = XKeysymToString(keysym);
if (keypress_func)
(*keypress_func) (keypress_data, ev->xkey.window, key);
else
{
if (last_gadget &&
((GadGeneral *) last_gadget)->type == E_TEXTBOX)
{
Epplet_textbox_handle_keyevent(ev, last_gadget);
Epplet_draw_textbox(last_gadget);
}
}
}
}
break;
case KeyRelease:
{
char *key;
KeySym keysym;
keysym = XkbKeycodeToKeysym(disp, ev->xkey.keycode, 0, 0);
key = XKeysymToString(keysym);
if (keyrelease_func)
(*keyrelease_func) (keyrelease_data, ev->xkey.window, key);
}
break;
case ButtonPress:
if (XFindContext(disp, ev->xkey.window, xid_context,
(XPointer *) & g) == XCNOENT)
g = NULL;
if (g)
Epplet_event(g, ev);
else
{
if (buttonpress_func)
(*buttonpress_func) (buttonpress_data, ev->xbutton.window,
ev->xbutton.x, ev->xbutton.y,
ev->xbutton.button);
}
break;
case ButtonRelease:
if (XFindContext(disp, ev->xkey.window, xid_context,
(XPointer *) & g) == XCNOENT)
g = NULL;
if (g)
{
last_gadget = g;
Epplet_event(g, ev);
}
else
{
if (buttonrelease_func)
(*buttonrelease_func) (buttonrelease_data, ev->xbutton.window,
ev->xbutton.x, ev->xbutton.y,
ev->xbutton.button);
}
break;
case MotionNotify:
if (XFindContext(disp, ev->xkey.window, xid_context,
(XPointer *) & g) == XCNOENT)
g = NULL;
if (g)
Epplet_event(g, ev);
else
{
if (mousemotion_func)
(*mousemotion_func) (mousemotion_data, ev->xmotion.window,
ev->xmotion.x, ev->xmotion.y);
}
break;
case EnterNotify:
if (XFindContext(disp, ev->xkey.window, xid_context,
(XPointer *) & g) == XCNOENT)
g = NULL;
if (g)
Epplet_event(g, ev);
else
{
if (enter_func)
(*enter_func) (enter_data, ev->xcrossing.window);
}
break;
case LeaveNotify:
if (XFindContext(disp, ev->xkey.window, xid_context,
(XPointer *) & g) == XCNOENT)
g = NULL;
if (g)
Epplet_event(g, ev);
else
{
if (leave_func)
(*leave_func) (leave_data, ev->xcrossing.window);
}
break;
case FocusIn:
if (focusin_func)
(*focusin_func) (focusin_data, ev->xfocus.window);
break;
case FocusOut:
last_gadget = NULL;
if (focusout_func)
(*focusout_func) (focusout_data, ev->xfocus.window);
break;
case Expose:
if (expose_func)
(*expose_func) (expose_data, ev->xexpose.window,
ev->xexpose.x, ev->xexpose.y,
ev->xexpose.width, ev->xexpose.height);
break;
case ConfigureNotify:
if (moveresize_func)
(*moveresize_func) (moveresize_data, ev->xconfigure.window,
ev->xconfigure.x, ev->xconfigure.y,
ev->xconfigure.width, ev->xconfigure.height);
break;
case PropertyNotify:
if (CommsHandlePropertyNotify(ev))
Epplet_redraw();
break;
case DestroyNotify:
CommsHandleDestroy(ev->xdestroywindow.window);
break;
default:
break;
}
}
void
Epplet_timer(void (*func)(void *data), void *data, double in,
const char *name)
{
ETimer *et, *ptr, *pptr;
double tally;
Epplet_remove_timer(name);
et = malloc(sizeof(ETimer));
et->next = NULL;
et->func = func;
et->data = data;
et->name = malloc(strlen(name) + 1);
et->just_added = 1;
et->in = in;
memcpy(et->name, name, strlen(name) + 1);
tally = 0.0;
if (!q_first)
q_first = et;
else
{
pptr = NULL;
ptr = q_first;
tally = 0.0;
while (ptr)
{
tally += ptr->in;
if (tally > in)
{
tally -= ptr->in;
et->next = ptr;
if (pptr)
pptr->next = et;
else
q_first = et;
et->in -= tally;
if (et->next)
et->next->in -= et->in;
return;
}
pptr = ptr;
ptr = ptr->next;
}
if (pptr)
pptr->next = et;
else
q_first = et;
et->in -= tally;
}
}
void
Epplet_remove_timer(const char *name)
{
ETimer *et, *ptr, *pptr;
pptr = NULL;
ptr = q_first;
while (ptr)
{
et = ptr;
if (!strcmp(et->name, name))
{
if (pptr)
pptr->next = et->next;
else
q_first = et->next;
if (et->next)
et->next->in += et->in;
free(et->name);
free(et);
return;
}
pptr = ptr;
ptr = ptr->next;
}
}
void *
Epplet_timer_get_data(const char *name)
{
ETimer *et, *ptr;
ptr = q_first;
while (ptr)
{
et = ptr;
if (!strcmp(et->name, name))
{
return et->data;
}
ptr = ptr->next;
}
return NULL;
}
static void
Epplet_handle_timer(void)
{
ETimer *et;
if (!q_first)
return;
et = q_first;
q_first = q_first->next;
(*(et->func)) (et->data);
if (et && et->name)
free(et->name);
free(et);
}
double
Epplet_get_time(void)
{
struct timeval timev;
gettimeofday(&timev, NULL);
return (double)timev.tv_sec + (((double)timev.tv_usec) / 1000000);
}
static ETimer *
Epplet_get_first(void)
{
return q_first;
}
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
void
Epplet_prune_events(XEvent * ev, int num)
{
int i, j;
char found;
/* find only the last moption event */
found = 0;
for (i = num - 1; i >= 0; i--)
{
if (ev[i].type == MotionNotify)
{
if (!found)
found = 1;
else
ev[i].type = 0;
}
}
/* find all expose events and then all following expose events for that */
/* window then do a bounding box grow of the original expose event */
for (i = num - 1; i >= 0; i--)
{
if (ev[i].type == Expose)
{
for (j = i - 1; j >= 0; j--)
{
if ((ev[j].type == Expose) &&
(ev[j].xexpose.window == ev[i].xexpose.window))
{
if (ev[j].xexpose.x < ev[i].xexpose.x)
{
ev[i].xexpose.width +=
(ev[i].xexpose.x - ev[j].xexpose.x);
ev[i].xexpose.x = ev[j].xexpose.x;
}
if ((ev[j].xexpose.x + ev[j].xexpose.width) >
(ev[i].xexpose.x + ev[i].xexpose.width))
ev[i].xexpose.width +=
(ev[j].xexpose.x + ev[j].xexpose.width) -
(ev[i].xexpose.x + ev[i].xexpose.width);
if (ev[j].xexpose.y < ev[i].xexpose.y)
{
ev[i].xexpose.height +=
(ev[i].xexpose.y - ev[j].xexpose.y);
ev[i].xexpose.y = ev[j].xexpose.y;
}
if ((ev[j].xexpose.y + ev[j].xexpose.height) >
(ev[i].xexpose.y + ev[i].xexpose.height))
ev[i].xexpose.height +=
(ev[j].xexpose.y + ev[j].xexpose.height) -
(ev[i].xexpose.y + ev[i].xexpose.height);
ev[j].type = 0;
}
}
}
}
}
void
Epplet_Loop(void)
{
int xfd, fdsize, count;
double t1 = 0.0, t2 = 0.0, pt;
ETimer *et;
fd_set fdset;
struct timeval tval;
xfd = ConnectionNumber(disp);
fdsize = xfd + 1;
pt = Epplet_get_time();
for (;;)
{
XEvent *evs = NULL;
int evs_num = 0, i;
XFlush(disp);
t1 = Epplet_get_time();
t2 = t1 - pt;
pt = t1;
while (XPending(disp))
{
evs_num++;
if (evs)
evs = realloc(evs, sizeof(XEvent) * evs_num);
else
evs = malloc(sizeof(XEvent));
XNextEvent(disp, &(evs[evs_num - 1]));
}
if (evs)
{
Epplet_prune_events(evs, evs_num);
for (i = 0; i < evs_num; i++)
{
if (evs[i].type > 0)
Epplet_handle_event(&(evs[i]));
}
free(evs);
evs = NULL;
evs_num = 0;
}
XFlush(disp);
FD_ZERO(&fdset);
FD_SET(xfd, &fdset);
et = Epplet_get_first();
count = 0;
if (et)
{
if (et->just_added)
{
et->just_added = 0;
t1 = et->in;
}
else
{
t1 = et->in - t2;
if (t1 < 0.0)
t1 = 0.0;
et->in = t1;
}
tval.tv_sec = (long)t1;
tval.tv_usec = (long)((t1 - ((double)tval.tv_sec)) * 1000000);
if (tval.tv_sec < 0)
tval.tv_sec = 0;
if (tval.tv_usec <= 1000)
tval.tv_usec = 1000;
count = select(fdsize, &fdset, NULL, NULL, &tval);
}
else
count = select(fdsize, &fdset, NULL, NULL, NULL);
if (count < 0)
{
if ((errno == ENOMEM) || (errno == EINVAL) || (errno == EBADF))
exit(1);
}
else
{
if ((et) && (count == 0))
Epplet_handle_timer();
}
}
}
static void
CommsSetup(void)
{
for (;;)
{
CommsFindCommsWindow();
if (comms_win != None)
break;
sleep(1);
}
if (!my_win)
{
my_win = XCreateSimpleWindow(dd, root, -100, -100, 5, 5, 0, 0, 0);
XSelectInput(dd, my_win, StructureNotifyMask | SubstructureNotifyMask);
}
}
static void
CommsHandleDestroy(Window win)
{
if (win == comms_win)
comms_win = 0;
}
static int
CommsHandlePropertyNotify(XEvent * ev)
{
Atom a = 0;
if (comms_win)
return 0;
if (!a)
a = XInternAtom(dd, "ENLIGHTENMENT_COMMS", True);
if (a == ev->xproperty.atom)
CommsSetup();
if (comms_win)
return 1;
return 0;
}
static void
CommsFindCommsWindow(void)
{
unsigned char *s;
Atom a, ar;
unsigned long num, after;
int format;
Window rt;
int dint;
unsigned int duint;
a = XInternAtom(dd, "ENLIGHTENMENT_COMMS", True);
if (a != None)
{
s = NULL;
XGetWindowProperty(dd, root, a, 0, 14, False, AnyPropertyType, &ar,
&format, &num, &after, &s);
if (s)
{
sscanf((char *)s, "%*s %x", (unsigned int *)&comms_win);
XFree(s);
}
else
comms_win = 0;
if (comms_win)
{
if (!XGetGeometry(dd, comms_win, &rt, &dint, &dint,
&duint, &duint, &duint, &duint))
comms_win = 0;
s = NULL;
if (comms_win)
{
XGetWindowProperty(dd, comms_win, a, 0, 14, False,
AnyPropertyType, &ar, &format, &num,
&after, &s);
if (s)
XFree(s);
else
comms_win = 0;
}
}
}
if (comms_win)
XSelectInput(dd, comms_win, StructureNotifyMask | SubstructureNotifyMask);
}
void
Epplet_send_ipc(const char *fmt, ...)
{
static Atom a = None;
va_list args;
char buf[1024];
char ss[21];
int i, j, k, len;
XEvent ev;
if (!fmt || !dd)
return;
if (!a)
a = XInternAtom(dd, "ENL_MSG", False);
va_start(args, fmt);
len = vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
if (len >= (int)sizeof(buf))
len = sizeof(buf) - 1;
ev.xclient.type = ClientMessage;
ev.xclient.serial = 0;
ev.xclient.send_event = True;
ev.xclient.window = comms_win;
ev.xclient.message_type = a;
ev.xclient.format = 8;
for (i = 0; i < len + 1; i += 12)
{
snprintf(ss, sizeof(ss), "%8x", (int)my_win);
for (j = 0; j < 12; j++)
{
ss[8 + j] = buf[i + j];
if (!buf[i + j])
j = 12;
}
ss[20] = 0;
for (k = 0; k < 20; k++)
ev.xclient.data.b[k] = ss[k];
XSendEvent(dd, comms_win, False, 0, (XEvent *) & ev);
}
}
static Bool
ev_check(Display * d __UNUSED__, XEvent * ev, XPointer p __UNUSED__)
{
if (((ev->type == ClientMessage) && (ev->xclient.window == my_win)) ||
((ev->type == DestroyNotify) &&
(ev->xdestroywindow.window == comms_win)))
return True;
return False;
}
static char *
ECommsWaitForMessage(void)
{
XEvent ev;
char *msg = NULL;
while ((!msg) && (comms_win))
{
XIfEvent(dd, &ev, ev_check, NULL);
if (ev.type == DestroyNotify)
comms_win = 0;
else
msg = ECommsGet(&ev);
}
return msg;
}
static char *
ECommsGet(XEvent * ev)
{
char s[13], s2[9], *msg = NULL;
int i;
Window win = 0;
static char *c_msg = NULL;
if (!ev)
return NULL;
if (ev->type != ClientMessage)
return NULL;
s[12] = 0;
s2[8] = 0;
msg = NULL;
for (i = 0; i < 8; i++)
s2[i] = ev->xclient.data.b[i];
for (i = 0; i < 12; i++)
s[i] = ev->xclient.data.b[i + 8];
sscanf(s2, "%x", (int *)&win);
if (win == comms_win)
{
if (c_msg)
{
c_msg = realloc(c_msg, strlen(c_msg) + strlen(s) + 1);
if (!c_msg)
return NULL;
strcat(c_msg, s);
}
else
{
c_msg = malloc(strlen(s) + 1);
if (!c_msg)
return NULL;
strcpy(c_msg, s);
}
if (strlen(s) < 12)
{
msg = c_msg;
c_msg = NULL;
}
}
return msg;
}
int
Epplet_get_color(int r, int g, int b)
{
XColor xc;
xc.red = (r << 8) | r;
xc.green = (g << 8) | g;
xc.blue = (b << 8) | b;
XAllocColor(disp, imlib_context_get_colormap(), &xc);
return xc.pixel;
}
static char *
Estrdup(const char *s)
{
char *ss;
int len;
if (!s)
return NULL;
len = strlen(s);
ss = malloc(len + 1);
memcpy(ss, s, len + 1);
return ss;
}
static char *
Epplet_find_file(const char *name)
{
char s[1024];
struct stat st;
if (!name)
return NULL;
/* Check if absolute path */
if (name[0] == '/')
return Estrdup(name);
/* Check if in epplet data dir */
snprintf(s, sizeof(s), "%s/%s", Epplet_data_dir(), name);
if (stat(s, &st) == 0)
return Estrdup(s);
/* Just dup and return */
return Estrdup(name);
}
void
Epplet_paste_image(const char *image, Window ww, int x, int y)
{
Imlib_Image *im;
im = imlib_load_image(image);
if (im)
{
imlib_context_set_image(im);
imlib_context_set_drawable(ww);
imlib_render_image_on_drawable(x, y);
imlib_free_image();
}
}
void
Epplet_paste_image_size(const char *image, Window ww, int x, int y, int w,
int h)
{
Imlib_Image *im;
im = imlib_load_image(image);
if (im)
{
imlib_context_set_image(im);
imlib_context_set_drawable(ww);
imlib_render_image_on_drawable_at_size(x, y, w, h);
imlib_free_image();
}
}
void
Epplet_add_gad(Epplet_gadget gadget)
{
gad_num++;
if (gads)
gads = realloc(gads, gad_num * sizeof(Epplet_gadget));
else
gads = malloc(gad_num * sizeof(Epplet_gadget));
gads[gad_num - 1] = gadget;
}
void
Epplet_del_gad(Epplet_gadget gadget)
{
int i, j;
for (i = 0; i < gad_num; i++)
{
if (gads[i] == gadget)
{
for (j = i; j < gad_num - 1; j++)
gads[j] = gads[j + 1];
gad_num--;
if (gad_num > 0)
gads = realloc(gads, gad_num * sizeof(Epplet_gadget));
else
{
free(gads);
gads = NULL;
}
}
}
}
int
Epplet_gadget_get_x(Epplet_gadget gad)
{
GadImage *g; /* Lowest common denominator */
g = (GadImage *) gad;
return (g->x);
}
int
Epplet_gadget_get_y(Epplet_gadget gad)
{
GadImage *g; /* Lowest common denominator */
g = (GadImage *) gad;
return (g->y);
}
int
Epplet_gadget_get_width(Epplet_gadget gad)
{
GadImage *g; /* Lowest common denominator */
g = (GadImage *) gad;
return (g->w);
}
int
Epplet_gadget_get_height(Epplet_gadget gad)
{
GadImage *g; /* Lowest common denominator */
g = (GadImage *) gad;
return (g->h);
}
int
Epplet_gadget_get_type(Epplet_gadget gad)
{
return gad ? (int)GADGET_GET_TYPE(gad) : -1;
}
Epplet_gadget
Epplet_create_textbox(const char *image, const char *contents, int x, int y,
int w, int h, char size, void (*func)(void *data),
void *data)
{
GadTextBox *g;
XSetWindowAttributes attr;
int contents_w, contents_h;
g = malloc(sizeof(GadTextBox));
g->general.type = E_TEXTBOX;
g->general.parent = context_win;
g->x = x;
g->y = y;
g->contents = Estrdup(contents);
g->cursor_pos = contents ? strlen(contents) : 0;
g->x_offset = 0;
g->w = w;
g->h = h;
g->size = size;
g->func = func;
g->data = data;
g->pmap = 0;
g->mask = 0;
g->image = Epplet_find_file(image);
g->hilited = 0;
if (contents)
{
Epplet_textbox_textsize(g, &contents_w, &contents_h, contents);
g->to_cursor = contents_w;
}
else
g->to_cursor = 0;
attr.backing_store = NotUseful;
attr.override_redirect = False;
attr.colormap = imlib_context_get_colormap();
attr.border_pixel = 0;
attr.background_pixel = 0;
attr.save_under = False;
attr.event_mask =
EnterWindowMask | LeaveWindowMask | ButtonPressMask | ButtonReleaseMask |
KeyPressMask | KeyReleaseMask;
g->general.visible = 0;
g->win = XCreateWindow(disp, context_win->win, x, y, g->w, g->h, 0,
CopyFromParent, InputOutput, CopyFromParent,
CWOverrideRedirect | CWSaveUnder | CWBackingStore |
CWColormap | CWBackPixel | CWBorderPixel |
CWEventMask, &attr);
XSaveContext(disp, g->win, xid_context, (XPointer) g);
Epplet_add_gad((Epplet_gadget) g);
return (Epplet_gadget) g;
}
const char *
Epplet_textbox_contents(Epplet_gadget eg)
{
GadTextBox *g;
g = (GadTextBox *) eg;
GADGET_CONFIRM_TYPE_RVAL(eg, E_TEXTBOX, (char *)NULL);
return ((g->contents) ? (g->contents) : "");
}
void
Epplet_reset_textbox(Epplet_gadget eg)
{
GadTextBox *g;
g = (GadTextBox *) eg;
GADGET_CONFIRM_TYPE(eg, E_TEXTBOX);
if (g->contents)
{
free(g->contents);
g->contents = NULL;
}
g->cursor_pos = g->x_offset = g->to_cursor = 0;
Epplet_draw_textbox(eg);
}
void
Epplet_textbox_insert(Epplet_gadget eg, const char *new_contents)
{
GadTextBox *g;
int len, w, h;
char *s, *line_break;
GADGET_CONFIRM_TYPE(eg, E_TEXTBOX);
if (!new_contents || ((len = strlen(new_contents)) == 0))
return;
g = (GadTextBox *) eg;
if (g->contents)
s = malloc(len + strlen(g->contents) + 1);
else
s = malloc(len + 1);
if ((line_break = strchr(new_contents, '\n')))
{
*line_break = '\0'; /* get rid of the new line */
}
if (s)
{
*s = '\0';
if (g->contents)
{
strncpy(s, g->contents, g->cursor_pos);
*(s + g->cursor_pos) = '\0';
strcat(s, new_contents);
strcat(s, (g->contents + g->cursor_pos + 1));
}
else
strcat(s, new_contents);
free(g->contents);
g->contents = s;
}
else
{
printf("Couldn't alloc mem\n");
return;
}
if (line_break)
{
if (g->func)
(*(g->func)) (g->data);
}
Epplet_textbox_textsize(g, &w, &h, g->contents);
g->cursor_pos = g->contents ? strlen(g->contents) : 0;
g->x_offset = 0;
if (w > g->w)
g->x_offset -= w - g->w + 2 + CRSR_WDTH;
g->to_cursor = w;
Epplet_draw_textbox(eg);
}
void
Epplet_change_textbox(Epplet_gadget eg, const char *new_contents)
{
GadTextBox *g;
int len, w, h;
char *s;
GADGET_CONFIRM_TYPE(eg, E_TEXTBOX);
if (!new_contents || ((len = strlen(new_contents)) == 0))
{
Epplet_reset_textbox(eg);
return;
}
g = (GadTextBox *) eg;
if (g->contents == new_contents)
return;
free(g->contents);
if ((s = strchr(new_contents, '\n')))
{
*s = '\0'; /* kill new line */
s = malloc(sizeof(char) * len + 1);
if (s)
{
strcpy(s, new_contents);
g->contents = s;
Epplet_draw_textbox(eg);
if (g->func)
(*(g->func)) (g->data);
}
else
printf("Couldn't allocate memory.\n");
}
g->contents = Estrdup(new_contents);
Epplet_textbox_textsize(g, &w, &h, g->contents);
g->cursor_pos = g->contents ? strlen(g->contents) : 0;
g->x_offset = 0;
if (w > g->w)
g->x_offset -= w - g->w + 2 + CRSR_WDTH;
g->to_cursor = w;
g->cursor_pos = strlen(new_contents);
Epplet_draw_textbox(eg);
}
void
Epplet_draw_textbox(Epplet_gadget eg)
{
GadTextBox *g;
const char *state;
unsigned long gc_valuemask = 0;
XGCValues gc_values;
GC gc;
GADGET_CONFIRM_TYPE(eg, E_TEXTBOX);
if (!(g = (GadTextBox *) eg))
return;
if (g->hilited)
state = "hilited";
else
state = "normal";
if (g->pmap)
XFreePixmap(disp, g->pmap);
if (g->mask)
XFreePixmap(disp, g->mask);
g->pmap = 0;
g->mask = 0;
Epplet_imageclass_get_pixmaps("EPPLET_BUTTON", "clicked",
&(g->pmap), &(g->mask), g->w, g->h);
if (g->image)
{
Imlib_Image *im;
ESYNC;
im = imlib_load_image(g->image);
if (im)
{
int x, y, w, h;
imlib_context_set_image(im);
if (g->w > imlib_image_get_width())
{
w = imlib_image_get_width();
x = (g->w - imlib_image_get_width()) / 2;
}
else
{
w = g->w - 4;
x = 2;
}
if (g->h > imlib_image_get_height())
{
h = imlib_image_get_height();
y = (g->h - imlib_image_get_height()) / 2;
}
else
{
h = g->h - 4;
y = 2;
}
imlib_context_set_drawable(g->pmap);
imlib_render_image_on_drawable_at_size(x, y, w, h);
imlib_free_image();
}
}
if (g->contents)
{
int x, y, h;
char *s, temp;
/* Save the character under the cursor */
temp = g->contents[g->cursor_pos];
/* nullify the character under the cursor */
g->contents[g->cursor_pos] = '\0';
/* s now points to a string ending at the cursor */
s = Estrdup(g->contents);
/* undo our change */
g->contents[g->cursor_pos] = temp;
/* Get the position in pixels to the cursor */
Epplet_textbox_textsize(eg, &x, &h, s);
g->to_cursor = x;
free(s);
if (h == 0)
Epplet_textbox_textsize(eg, &x, &h, "X");
x = g->x_offset + 2;
y = (g->h - h) / 2;
switch (g->size)
{
case 0:
Epplet_textclass_draw("EPPLET_BUTTON", state, g->pmap, x, y,
g->contents);
break;
case 1:
Epplet_textclass_draw("EPPLET_TEXT_TINY", state, g->pmap, x, y,
g->contents);
break;
case 2:
Epplet_textclass_draw("EPPLET_TEXT_MEDIUM", state, g->pmap, x, y,
g->contents);
break;
case 3:
Epplet_textclass_draw("EPPLET_TEXT_LARGE", state, g->pmap, x, y,
g->contents);
break;
}
}
ESYNC;
XSetWindowBackgroundPixmap(disp, g->win, g->pmap);
XShapeCombineMask(disp, g->win, ShapeBounding, 0, 0, g->mask, ShapeSet);
XClearWindow(disp, g->win);
gc_valuemask = GCFunction;
gc_values.function = GXinvert;
gc = XCreateGC(disp, g->win, gc_valuemask, &gc_values);
XSetForeground(disp, gc, Epplet_get_color(0, 0, 0));
if ((last_gadget == g) || (g->hilited))
XFillRectangle(disp, g->win, gc, g->to_cursor + g->x_offset + 2, 2,
CRSR_WDTH, g->h - 4);
#if 0
/* That empty cursor is REALLY obnoxious. Punt it. */
else
XDrawRectangle(disp, g->win, gc, g->to_cursor + g->x_offset + 2, 2,
CRSR_WDTH, g->h - 4);
#endif
EXFreeGC(gc);
}
int
Epplet_textbox_spacesize(Epplet_gadget gadget)
{
const char *s1 = "Z Z";
const char *s2 = "ZZ";
int size1, size2, h;
GadTextBox *g;
g = (GadTextBox *) gadget;
GADGET_CONFIRM_TYPE_RVAL(gadget, E_TEXTBOX, -1);
Epplet_textbox_textsize(g, &size1, &h, s1);
Epplet_textbox_textsize(g, &size2, &h, s2);
return (size1 - size2);
}
static void
Epplet_textbox_textsize(Epplet_gadget gadget, int *w, int *h, const char *s)
{
GadTextBox *g;
g = (GadTextBox *) gadget;
switch (g->size)
{
case 0:
Epplet_textclass_get_size("EPPLET_BUTTON", w, h, s);
break;
case 1:
Epplet_textclass_get_size("EPPLET_TEXT_TINY", w, h, s);
break;
case 2:
Epplet_textclass_get_size("EPPLET_TEXT_MEDIUM", w, h, s);
break;
case 3:
Epplet_textclass_get_size("EPPLET_TEXT_LARGE", w, h, s);
break;
}
}
static void
Epplet_textbox_handle_keyevent(XEvent * ev, Epplet_gadget gadget)
{
int len, char_width, text_width, h;
static char kbuf[20];
KeySym keysym;
GadTextBox *g;
g = (GadTextBox *) gadget;
len = XLookupString(&ev->xkey, (char *)kbuf, sizeof(kbuf), &keysym, NULL);
/* Convert unmapped Latin2-4 keysyms into Latin1 characters */
if (!len && (keysym >= 0x0100) && (keysym < 0x0400))
{
len = 1;
kbuf[0] = (keysym & 0xff);
}
switch (keysym)
{
case XK_Left:
{
char s[2];
if (g->cursor_pos > 0)
{
--g->cursor_pos;
if (g->contents && *(g->contents) && (g->x_offset < 0))
{
if (g->contents[strlen(g->contents) - 1] == ' ')
char_width = Epplet_textbox_spacesize(g);
else
{
s[0] = *(g->contents + g->cursor_pos - 1);
s[1] = '\0';
Epplet_textbox_textsize(g, &char_width, &h, s);
}
if (((int)g->to_cursor + g->x_offset) <= 2)
g->x_offset += char_width;
if (g->cursor_pos == 0)
g->x_offset = 0;
}
}
return;
break;
}
case XK_Right:
{
char s[2];
if (g->contents && (g->cursor_pos < strlen(g->contents)))
++g->cursor_pos;
Epplet_textbox_textsize(g, &text_width, &h, g->contents);
if ((int)(g->to_cursor + g->x_offset) >= (g->w - CRSR_WDTH - 5))
{
s[0] = *(g->contents + g->cursor_pos + 1);
s[1] = '\0';
if (s[0] == ' ')
char_width = Epplet_textbox_spacesize(g);
else
Epplet_textbox_textsize(g, &char_width, &h, s);
if (((int)g->to_cursor + g->x_offset + CRSR_WDTH) >=
(g->w - CRSR_WDTH - 5))
g->x_offset -= char_width;
}
return;
break;
}
case XK_Delete:
{
if (g->contents && *(g->contents)
&& (g->cursor_pos < strlen(g->contents)))
{
int contents_len;
contents_len = strlen(g->contents) - 1;
memmove((g->contents + g->cursor_pos),
(g->contents + g->cursor_pos + 1),
strlen(g->contents + g->cursor_pos + 1));
g->contents = realloc(g->contents, strlen(g->contents));
*(g->contents + contents_len) = '\0';
}
return;
break;
}
case XK_Home:
case XK_KP_Home:
{
if (g->contents)
g->cursor_pos = g->to_cursor = g->x_offset = 0;
break;
}
case XK_End:
case XK_KP_End:
{
int ww, hh;
if (g->contents && (g->cursor_pos != strlen(g->contents)))
{
g->cursor_pos = strlen(g->contents);
Epplet_textbox_textsize(g, &ww, &hh, g->contents);
g->x_offset = 0;
if (ww > g->w)
g->x_offset -= ww - g->w + CRSR_WDTH + 5;
g->to_cursor = ww;
}
}
default:
break;
}
if (len <= 0 || len > (int)sizeof(kbuf))
return;
kbuf[len] = 0;
if (*kbuf == '\r' || *kbuf == '\n')
{
if (g->func)
(*(g->func)) (g->data);
}
else if (*kbuf == '\b')
{
if (g->contents && *(g->contents) && (g->cursor_pos > 0))
{
char *s;
s = malloc(strlen(g->contents) + 1);
*(g->contents + g->cursor_pos - 1) = '\0';
sprintf(s, "%s%s", g->contents, (g->contents + g->cursor_pos));
free(g->contents);
g->contents = s;
if (g->cursor_pos > 0)
g->cursor_pos--;
if (g->cursor_pos == 0)
g->x_offset = 0;
}
}
else
{
if (g->contents)
{
g->contents =
realloc(g->contents, (strlen(g->contents) + len + 1));
}
else
{
if (!strcmp(kbuf, " "))
return;
g->contents = malloc(len + 1);
*(g->contents) = '\0';
}
len = strlen(g->contents) + 1;
memmove((g->contents + g->cursor_pos + 1),
(g->contents + g->cursor_pos),
strlen(g->contents + g->cursor_pos));
*(g->contents + g->cursor_pos) = *kbuf;
*(g->contents + len) = '\0';
g->cursor_pos++;
}
Epplet_textbox_textsize(g, &char_width, &h, kbuf);
Epplet_textbox_textsize(g, &text_width, &h, g->contents);
if (*kbuf == ' ')
char_width = Epplet_textbox_spacesize(g);
if ((*kbuf == '\b') && g->contents && *(g->contents))
{
if (g->x_offset < 0)
{
if (*(g->contents + strlen(g->contents)) == ' ')
char_width = Epplet_textbox_spacesize(g);
else
Epplet_textbox_textsize(g, &char_width, &h,
&g->contents[strlen(g->contents) - 1]);
if (((int)g->to_cursor + g->x_offset) <= 2)
g->x_offset += char_width;
if (g->cursor_pos == 0)
g->x_offset = 0;
}
}
else if (((int)g->to_cursor + g->x_offset) >= (g->w - CRSR_WDTH - 2))
g->x_offset -= char_width;
}
Epplet_gadget
Epplet_create_button(const char *label, const char *image, int x, int y,
int w, int h, const char *std, Window parent,
Epplet_gadget pop_parent,
void (*func)(void *data), void *data)
{
GadButton *g;
XSetWindowAttributes attr;
g = malloc(sizeof(GadButton));
g->general.type = E_BUTTON;
g->general.parent = context_win;
g->x = x;
g->y = y;
g->std = Estrdup(std);
if (g->std)
{
g->w = 12;
g->h = 12;
}
else
{
g->w = w;
g->h = h;
}
g->func = func;
g->data = data;
g->pmap = 0;
g->mask = 0;
g->label = Estrdup(label);
g->image = Epplet_find_file(image);
g->hilited = 0;
g->clicked = 0;
g->pop = 0;
g->pop_parent = pop_parent;
attr.backing_store = NotUseful;
attr.override_redirect = False;
attr.colormap = imlib_context_get_colormap();
attr.border_pixel = 0;
attr.background_pixel = 0;
attr.save_under = False;
attr.event_mask = ButtonPressMask | ButtonReleaseMask |
EnterWindowMask | LeaveWindowMask;
g->general.visible = 0;
if (parent)
{
g->win = XCreateWindow(disp, parent, x, y, g->w, g->h, 0,
CopyFromParent, InputOutput, CopyFromParent,
CWOverrideRedirect | CWSaveUnder |
CWBackingStore | CWColormap | CWBackPixel |
CWBorderPixel | CWEventMask, &attr);
g->pop = 1;
}
else
g->win = XCreateWindow(disp, context_win->win, x, y, g->w, g->h, 0,
CopyFromParent, InputOutput, CopyFromParent,
CWOverrideRedirect | CWSaveUnder | CWBackingStore
| CWColormap | CWBackPixel | CWBorderPixel |
CWEventMask, &attr);
XSaveContext(disp, g->win, xid_context, (XPointer) g);
Epplet_add_gad((Epplet_gadget) g);
return (Epplet_gadget) g;
}
/* A cut down version for text-only buttons */
Epplet_gadget
Epplet_create_text_button(const char *label, int x, int y,
int w, int h, void (*func)(void *data), void *data)
{
return Epplet_create_button(label, NULL, x, y, w, h, NULL, 0, NULL, func,
data);
}
/* A cut down version for stdimage-only buttons */
Epplet_gadget
Epplet_create_std_button(const char *std, int x, int y,
void (*func)(void *data), void *data)
{
return Epplet_create_button(NULL, NULL, x, y, 12, 12, std, 0, NULL, func,
data);
}
/* A cut down version for image-only buttons */
Epplet_gadget
Epplet_create_image_button(const char *image, int x, int y,
int w, int h, void (*func)(void *data), void *data)
{
return Epplet_create_button(NULL, image, x, y, w, h, NULL, 0, NULL, func,
data);
}
void
Epplet_draw_button(Epplet_gadget eg)
{
GadButton *g;
const char *state;
g = (GadButton *) eg;
if (g->hilited)
{
if (g->clicked)
state = "clicked";
else
state = "hilited";
}
else
{
if (g->clicked)
state = "clicked";
else
state = "normal";
}
if (g->pmap)
XFreePixmap(disp, g->pmap);
if (g->mask)
XFreePixmap(disp, g->mask);
g->pmap = 0;
g->mask = 0;
if (g->std)
{
char s[1024];
snprintf(s, sizeof(s), "EPPLET_%s", g->std);
Epplet_imageclass_get_pixmaps(s, state,
&(g->pmap), &(g->mask), g->w, g->h);
}
else if (g->pop)
{
Epplet_imageclass_get_pixmaps("EPPLET_POPUP_ENTRY", state,
&(g->pmap), &(g->mask), g->w, g->h);
if (g->image)
{
Imlib_Image *im;
ESYNC;
im = imlib_load_image(g->image);
if (im)
{
int x, y, w, h;
imlib_context_set_image(im);
if (g->w > imlib_image_get_width())
{
w = imlib_image_get_width();
x = (g->w - imlib_image_get_width()) / 2;
}
else
{
w = g->w - 4;
x = 2;
}
if (g->h > imlib_image_get_height())
{
h = imlib_image_get_height();
y = (g->h - imlib_image_get_height()) / 2;
}
else
{
h = g->h - 4;
y = 2;
}
imlib_context_set_drawable(g->pmap);
imlib_render_image_on_drawable_at_size(x, y, w, h);
imlib_free_image();
}
}
if (g->label)
{
int x, y, w, h;
Epplet_textclass_get_size("EPPLET_POPUP", &w, &h, g->label);
x = (g->w - w) / 2;
y = (g->h - h) / 2;
Epplet_textclass_draw("EPPLET_POPUP", state, g->pmap, x, y,
g->label);
}
}
else
{
Epplet_imageclass_get_pixmaps("EPPLET_BUTTON", state,
&(g->pmap), &(g->mask), g->w, g->h);
if (g->image)
{
Imlib_Image *im;
ESYNC;
im = imlib_load_image(g->image);
if (im)
{
int x, y, w, h;
imlib_context_set_image(im);
if (g->w > imlib_image_get_width())
{
w = imlib_image_get_width();
x = (g->w - imlib_image_get_width()) / 2;
}
else
{
w = g->w - 4;
x = 2;
}
if (g->h > imlib_image_get_height())
{
h = imlib_image_get_height();
y = (g->h - imlib_image_get_height()) / 2;
}
else
{
h = g->h - 4;
y = 2;
}
imlib_context_set_drawable(g->pmap);
imlib_render_image_on_drawable_at_size(x, y, w, h);
imlib_free_image();
}
}
if (g->label)
{
int x, y, w, h;
Epplet_textclass_get_size("EPPLET_BUTTON", &w, &h, g->label);
x = (g->w - w) / 2;
y = (g->h - h) / 2;
Epplet_textclass_draw("EPPLET_BUTTON", state, g->pmap, x, y,
g->label);
}
}
ESYNC;
XSetWindowBackgroundPixmap(disp, g->win, g->pmap);
XShapeCombineMask(disp, g->win, ShapeBounding, 0, 0, g->mask, ShapeSet);
XClearWindow(disp, g->win);
}
Epplet_gadget
Epplet_create_togglebutton(const char *label, const char *image, int x,
int y, int w, int h, int *val,
void (*func)(void *data), void *data)
{
GadToggleButton *g;
XSetWindowAttributes attr;
g = malloc(sizeof(GadToggleButton));
g->general.type = E_TOGGLEBUTTON;
g->general.parent = context_win;
g->x = x;
g->y = y;
g->w = w;
g->h = h;
g->func = func;
g->data = data;
g->pmap = 0;
g->mask = 0;
g->val = val;
g->label = Estrdup(label);
g->image = Epplet_find_file(image);
g->hilited = 0;
g->clicked = 0;
attr.backing_store = NotUseful;
attr.override_redirect = False;
attr.colormap = imlib_context_get_colormap();
attr.border_pixel = 0;
attr.background_pixel = 0;
attr.save_under = False;
attr.event_mask = ButtonPressMask | ButtonReleaseMask |
EnterWindowMask | LeaveWindowMask;
g->general.visible = 0;
g->win = XCreateWindow(disp, context_win->win, x, y, w, h, 0,
CopyFromParent, InputOutput, CopyFromParent,
CWOverrideRedirect | CWSaveUnder | CWBackingStore |
CWColormap | CWBackPixel | CWBorderPixel |
CWEventMask, &attr);
XSaveContext(disp, g->win, xid_context, (XPointer) g);
Epplet_add_gad((Epplet_gadget) g);
return (Epplet_gadget) g;
}
void
Epplet_draw_togglebutton(Epplet_gadget eg)
{
GadToggleButton *g;
const char *state;
g = (GadToggleButton *) eg;
if (g->hilited)
{
if (g->clicked)
state = "clicked";
else
state = "hilited";
}
else
{
if (g->clicked)
state = "clicked";
else
state = "normal";
}
if (g->pmap)
XFreePixmap(disp, g->pmap);
if (g->mask)
XFreePixmap(disp, g->mask);
g->pmap = 0;
g->mask = 0;
if (*(g->val))
Epplet_imageclass_get_pixmaps("EPPLET_TOGGLEBUTTON_ON", state,
&(g->pmap), &(g->mask), g->w, g->h);
else
Epplet_imageclass_get_pixmaps("EPPLET_TOGGLEBUTTON_OFF", state,
&(g->pmap), &(g->mask), g->w, g->h);
if (g->image)
{
Imlib_Image *im;
ESYNC;
im = imlib_load_image(g->image);
if (im)
{
int x, y, w, h;
imlib_context_set_image(im);
if (g->w > imlib_image_get_width())
{
w = imlib_image_get_width();
x = (g->w - imlib_image_get_width()) / 2;
}
else
{
w = g->w - 4;
x = 2;
}
if (g->h > imlib_image_get_height())
{
h = imlib_image_get_height();
y = (g->h - imlib_image_get_height()) / 2;
}
else
{
h = g->h - 4;
y = 2;
}
imlib_context_set_drawable(g->pmap);
imlib_render_image_on_drawable_at_size(x, y, w, h);
imlib_free_image();
}
}
if (g->label)
{
int x, y, w, h;
if (*(g->val))
{
Epplet_textclass_get_size("EPPLET_TOGGLEBUTTON_ON", &w, &h,
g->label);
x = (g->w - w) / 2;
y = (g->h - h) / 2;
Epplet_textclass_draw("EPPLET_TOGGLEBUTTON_ON", state, g->pmap, x,
y, g->label);
}
else
{
Epplet_textclass_get_size("EPPLET_TOGGLEBUTTON_OFF", &w, &h,
g->label);
x = (g->w - w) / 2;
y = (g->h - h) / 2;
Epplet_textclass_draw("EPPLET_TOGGLEBUTTON_OFF", state, g->pmap, x,
y, g->label);
}
}
ESYNC;
XSetWindowBackgroundPixmap(disp, g->win, g->pmap);
XShapeCombineMask(disp, g->win, ShapeBounding, 0, 0, g->mask, ShapeSet);
XClearWindow(disp, g->win);
}
Epplet_gadget
Epplet_create_drawingarea(int x, int y, int w, int h)
{
GadDrawingArea *g;
XSetWindowAttributes attr;
g = malloc(sizeof(GadDrawingArea));
g->general.type = E_DRAWINGAREA;
g->general.parent = context_win;
g->x = x;
g->y = y;
g->w = w;
g->h = h;
attr.backing_store = NotUseful;
attr.override_redirect = False;
attr.colormap = imlib_context_get_colormap();
attr.border_pixel = 0;
attr.background_pixel = 0;
attr.save_under = False;
attr.event_mask = 0;
g->general.visible = 0;
g->win = XCreateWindow(disp, context_win->win, x, y, w, h, 0,
CopyFromParent, InputOutput, CopyFromParent,
CWOverrideRedirect | CWSaveUnder | CWBackingStore |
CWColormap | CWBackPixel | CWBorderPixel |
CWEventMask, &attr);
attr.event_mask = ButtonPressMask |
ButtonReleaseMask | PointerMotionMask | EnterWindowMask |
LeaveWindowMask | KeyPressMask | KeyReleaseMask | ButtonMotionMask |
ExposureMask;
g->win_in = XCreateWindow(disp, g->win, 2, 2, w - 4, h - 4, 0,
CopyFromParent, InputOutput, CopyFromParent,
CWOverrideRedirect | CWSaveUnder | CWBackingStore
| CWColormap | CWBackPixel | CWBorderPixel |
CWEventMask, &attr);
XSetWindowBackgroundPixmap(disp, g->win_in, ParentRelative);
XMapWindow(disp, g->win_in);
Epplet_add_gad((Epplet_gadget) g);
return (Epplet_gadget) g;
}
void
Epplet_draw_drawingarea(Epplet_gadget eg)
{
GadDrawingArea *g;
g = (GadDrawingArea *) eg;
Epplet_imageclass_apply("EPPLET_DRAWINGAREA", "normal", g->win);
}
Epplet_gadget
Epplet_create_hslider(int x, int y, int len, int min, int max,
int step, int jump, int *val,
void (*func)(void *data), void *data)
{
GadHSlider *g;
XSetWindowAttributes attr;
if (len < 9)
len = 9;
g = malloc(sizeof(GadHSlider));
g->general.type = E_HSLIDER;
g->general.parent = context_win;
g->x = x;
g->y = y;
g->w = len;
g->h = 8;
g->max = max;
g->min = min;
g->step = step;
g->jump = jump;
g->val = val;
g->func = func;
g->data = data;
g->hilited = 0;
g->clicked = 0;
attr.backing_store = NotUseful;
attr.override_redirect = False;
attr.colormap = imlib_context_get_colormap();
attr.border_pixel = 0;
attr.background_pixel = 0;
attr.save_under = False;
attr.event_mask = ButtonPressMask | ButtonReleaseMask;
g->general.visible = 0;
g->win = XCreateWindow(disp, context_win->win, x, y, len, 8, 0,
CopyFromParent, InputOutput, CopyFromParent,
CWOverrideRedirect | CWSaveUnder | CWBackingStore |
CWColormap | CWBackPixel | CWBorderPixel |
CWEventMask, &attr);
attr.event_mask = ButtonPressMask | ButtonReleaseMask |
PointerMotionMask | EnterWindowMask | LeaveWindowMask | ButtonMotionMask;
g->win_knob = XCreateWindow(disp, context_win->win, x, y, 8, 8, 0,
CopyFromParent, InputOutput, CopyFromParent,
CWOverrideRedirect | CWSaveUnder |
CWBackingStore | CWColormap | CWBackPixel |
CWBorderPixel | CWEventMask, &attr);
XSaveContext(disp, g->win, xid_context, (XPointer) g);
XSaveContext(disp, g->win_knob, xid_context, (XPointer) g);
Epplet_add_gad((Epplet_gadget) g);
return (Epplet_gadget) g;
}
void
Epplet_draw_hslider(Epplet_gadget eg)
{
GadHSlider *g;
const char *state;
g = (GadHSlider *) eg;
if (g->hilited)
{
if (g->clicked)
state = "clicked";
else
state = "hilited";
}
else
{
if (g->clicked)
state = "clicked";
else
state = "normal";
}
Epplet_imageclass_apply("EPPLET_HSLIDER_BASE", "normal", g->win);
XMoveWindow(disp, g->win_knob,
g->x + ((g->w - 8) * (*(g->val))) / (g->max - g->min + 1), g->y);
Epplet_imageclass_apply("EPPLET_HSLIDER_KNOB", state, g->win_knob);
}
Epplet_gadget
Epplet_create_vslider(int x, int y, int len, int min, int max,
int step, int jump, int *val,
void (*func)(void *data), void *data)
{
GadVSlider *g;
XSetWindowAttributes attr;
if (len < 9)
len = 9;
g = malloc(sizeof(GadVSlider));
g->general.type = E_VSLIDER;
g->general.parent = context_win;
g->x = x;
g->y = y;
g->w = 8;
g->h = len;
g->max = max;
g->min = min;
g->step = step;
g->jump = jump;
g->val = val;
g->func = func;
g->data = data;
g->hilited = 0;
g->clicked = 0;
attr.backing_store = NotUseful;
attr.override_redirect = False;
attr.colormap = imlib_context_get_colormap();
attr.border_pixel = 0;
attr.background_pixel = 0;
attr.save_under = False;
attr.event_mask = ButtonPressMask | ButtonReleaseMask;
g->general.visible = 0;
g->win = XCreateWindow(disp, context_win->win, x, y, 8, len, 0,
CopyFromParent, InputOutput, CopyFromParent,
CWOverrideRedirect | CWSaveUnder | CWBackingStore |
CWColormap | CWBackPixel | CWBorderPixel |
CWEventMask, &attr);
attr.event_mask = ButtonPressMask | ButtonReleaseMask |
PointerMotionMask | EnterWindowMask | LeaveWindowMask | ButtonMotionMask;
g->win_knob = XCreateWindow(disp, context_win->win, x, y, 8, 8, 0,
CopyFromParent, InputOutput, CopyFromParent,
CWOverrideRedirect | CWSaveUnder |
CWBackingStore | CWColormap | CWBackPixel |
CWBorderPixel | CWEventMask, &attr);
XSaveContext(disp, g->win, xid_context, (XPointer) g);
XSaveContext(disp, g->win_knob, xid_context, (XPointer) g);
Epplet_add_gad((Epplet_gadget) g);
return (Epplet_gadget) g;
}
void
Epplet_draw_vslider(Epplet_gadget eg)
{
GadVSlider *g;
const char *state;
g = (GadVSlider *) eg;
if (g->hilited)
{
if (g->clicked)
state = "clicked";
else
state = "hilited";
}
else
{
if (g->clicked)
state = "clicked";
else
state = "normal";
}
Epplet_imageclass_apply("EPPLET_VSLIDER_BASE", "normal", g->win);
XMoveWindow(disp, g->win_knob,
g->x, g->y + ((g->h - 8) * (*(g->val))) / (g->max - g->min + 1));
Epplet_imageclass_apply("EPPLET_VSLIDER_KNOB", state, g->win_knob);
}
Epplet_gadget
Epplet_create_hbar(int x, int y, int w, int h, char dir, int *val)
{
GadHBar *g;
XSetWindowAttributes attr;
g = malloc(sizeof(GadHBar));
g->general.type = E_HBAR;
g->general.parent = context_win;
g->x = x;
g->y = y;
g->w = w;
g->h = h;
g->dir = dir;
g->val = val;
attr.backing_store = NotUseful;
attr.override_redirect = False;
attr.colormap = imlib_context_get_colormap();
attr.border_pixel = 0;
attr.background_pixel = 0;
attr.save_under = False;
attr.event_mask = 0;
g->general.visible = 0;
g->win = XCreateWindow(disp, context_win->win, x, y, w, h, 0,
CopyFromParent, InputOutput, CopyFromParent,
CWOverrideRedirect | CWSaveUnder | CWBackingStore |
CWColormap | CWBackPixel | CWBorderPixel |
CWEventMask, &attr);
g->win_in = XCreateWindow(disp, g->win, 2, 2, w - 4, h - 4, 0,
CopyFromParent, InputOutput, CopyFromParent,
CWOverrideRedirect | CWSaveUnder | CWBackingStore
| CWColormap | CWBackPixel | CWBorderPixel |
CWEventMask, &attr);
XMapWindow(disp, g->win_in);
Epplet_add_gad((Epplet_gadget) g);
return (Epplet_gadget) g;
}
void
Epplet_draw_hbar(Epplet_gadget eg)
{
GadHBar *g;
int l;
g = (GadHBar *) eg;
l = (((g->w - 4) * (*(g->val))) / 100);
if (l < 1)
l = 1;
if (l > (g->w - 4))
l = g->w - 4;
if (g->dir)
XMoveResizeWindow(disp, g->win_in, g->w - 2 - l, 2, l, g->h - 4);
else
XMoveResizeWindow(disp, g->win_in, 2, 2, l, g->h - 4);
XSync(disp, False);
Epplet_imageclass_apply("EPPLET_HBAR_BASE", "normal", g->win);
Epplet_imageclass_apply("EPPLET_HBAR_BAR", "normal", g->win_in);
}
Epplet_gadget
Epplet_create_vbar(int x, int y, int w, int h, char dir, int *val)
{
GadVBar *g;
XSetWindowAttributes attr;
g = malloc(sizeof(GadVBar));
g->general.type = E_VBAR;
g->general.parent = context_win;
g->x = x;
g->y = y;
g->w = w;
g->h = h;
g->dir = dir;
g->val = val;
attr.backing_store = NotUseful;
attr.override_redirect = False;
attr.colormap = imlib_context_get_colormap();
attr.border_pixel = 0;
attr.background_pixel = 0;
attr.save_under = False;
attr.event_mask = 0;
g->general.visible = 0;
g->win = XCreateWindow(disp, context_win->win, x, y, w, h, 0,
CopyFromParent, InputOutput, CopyFromParent,
CWOverrideRedirect | CWSaveUnder | CWBackingStore |
CWColormap | CWBackPixel | CWBorderPixel |
CWEventMask, &attr);
g->win_in = XCreateWindow(disp, g->win, 2, 2, w - 4, h - 4, 0,
CopyFromParent, InputOutput, CopyFromParent,
CWOverrideRedirect | CWSaveUnder | CWBackingStore
| CWColormap | CWBackPixel | CWBorderPixel |
CWEventMask, &attr);
XMapWindow(disp, g->win_in);
Epplet_add_gad((Epplet_gadget) g);
return (Epplet_gadget) g;
}
void
Epplet_draw_vbar(Epplet_gadget eg)
{
GadVBar *g;
int l;
g = (GadVBar *) eg;
l = (((g->h - 4) * (*(g->val))) / 100);
if (l < 1)
l = 1;
if (l > (g->h - 4))
l = g->h - 4;
if (g->dir)
XMoveResizeWindow(disp, g->win_in, 2, g->h - 2 - l, g->w - 4, l);
else
XMoveResizeWindow(disp, g->win_in, 2, 2, g->w - 4, l);
XSync(disp, False);
Epplet_imageclass_apply("EPPLET_VBAR_BASE", "normal", g->win);
Epplet_imageclass_apply("EPPLET_VBAR_BAR", "normal", g->win_in);
}
Epplet_gadget
Epplet_create_image(int x, int y, int w, int h, const char *image)
{
GadImage *g;
g = malloc(sizeof(GadImage));
g->general.type = E_IMAGE;
g->general.parent = context_win;
g->general.visible = 0;
g->x = x;
g->y = y;
g->w = w;
g->h = h;
g->win = None;
g->pw = 0;
g->ph = 0;
g->image = Epplet_find_file(image);
Epplet_add_gad((Epplet_gadget) g);
return (Epplet_gadget) g;
}
void
Epplet_draw_image(Epplet_gadget eg, char un_only)
{
GadImage *g;
GC gc;
Imlib_Image *im;
g = (GadImage *) eg;
gc = EXCreateGC(g->general.parent->bg_pmap);
if ((g->pw > 0) && (g->ph > 0))
XCopyArea(disp, g->general.parent->bg_bg, g->general.parent->bg_pmap, gc,
g->x, g->y, g->pw, g->ph, g->x, g->y);
if (g->image && !un_only)
{
im = imlib_load_image(g->image);
if (im)
{
imlib_context_set_image(im);
imlib_context_set_drawable(g->general.parent->bg_pmap);
if ((g->w > 0) && (g->h > 0))
{
imlib_render_image_on_drawable_at_size(g->x, g->y, g->w,
g->h);
g->pw = g->w;
g->ph = g->h;
}
else
{
imlib_render_image_on_drawable(g->x, g->y);
g->pw = imlib_image_get_width();
g->ph = imlib_image_get_height();
}
imlib_free_image();
}
}
XSetWindowBackgroundPixmap(disp, g->general.parent->win,
g->general.parent->bg_pmap);
if (!un_only)
XClearWindow(disp, g->general.parent->win);
EXFreeGC(gc);
}
Epplet_gadget
Epplet_create_label(int x, int y, const char *label, char size)
{
GadLabel *g;
g = malloc(sizeof(GadLabel));
g->general.type = E_LABEL;
g->general.parent = context_win;
g->general.visible = 0;
g->x = x;
g->y = y;
g->win = None;
g->size = size;
g->label = Estrdup(label);
if (g->size == 0)
Epplet_textclass_get_size("EPPLET_LABEL", &(g->w), &(g->h), g->label);
else if (g->size == 1)
Epplet_textclass_get_size("EPPLET_TEXT_TINY", &(g->w), &(g->h), g->label);
else if (g->size == 2)
Epplet_textclass_get_size("EPPLET_TEXT_MEDIUM", &(g->w), &(g->h),
g->label);
else
Epplet_textclass_get_size("EPPLET_TEXT_LARGE", &(g->w), &(g->h),
g->label);
Epplet_add_gad((Epplet_gadget) g);
return (Epplet_gadget) g;
}
void
Epplet_draw_label(Epplet_gadget eg, char un_only)
{
GadLabel *g;
GC gc;
int x;
GADGET_CONFIRM_TYPE(eg, E_LABEL);
g = (GadLabel *) eg;
gc = EXCreateGC(g->general.parent->bg_pmap);
if (g->x < 0)
{
x = g->general.parent->w + g->x - g->w;
if (x < 0)
x = 0;
}
else
x = g->x;
XCopyArea(disp, g->general.parent->bg_bg, g->general.parent->bg_pmap, gc,
x - 1, g->y - 1, g->w + 2, g->h + 2, x - 1, g->y - 1);
if (!un_only)
{
XSync(disp, False);
if (g->size == 0)
{
Epplet_textclass_get_size("EPPLET_LABEL", &(g->w), &(g->h),
g->label);
if (g->x < 0)
{
x = g->general.parent->w + g->x - g->w;
if (x < 0)
x = 0;
}
else
x = g->x;
Epplet_textclass_draw("EPPLET_LABEL", "normal",
g->general.parent->bg_pmap, x, g->y,
g->label);
}
else if (g->size == 1)
{
Epplet_textclass_get_size("EPPLET_TEXT_TINY", &(g->w), &(g->h),
g->label);
if (g->x < 0)
{
x = g->general.parent->w + g->x - g->w;
if (x < 0)
x = 0;
}
else
x = g->x;
Epplet_textclass_draw("EPPLET_TEXT_TINY", "normal",
g->general.parent->bg_pmap, x, g->y,
g->label);
}
else if (g->size == 2)
{
Epplet_textclass_get_size("EPPLET_TEXT_MEDIUM", &(g->w), &(g->h),
g->label);
if (g->x < 0)
{
x = g->general.parent->w + g->x - g->w;
if (x < 0)
x = 0;
}
else
x = g->x;
Epplet_textclass_draw("EPPLET_TEXT_MEDIUM", "normal",
g->general.parent->bg_pmap, x, g->y,
g->label);
}
else
{
Epplet_textclass_get_size("EPPLET_TEXT_LARGE", &(g->w), &(g->h),
g->label);
if (g->x < 0)
{
x = g->general.parent->w + g->x - g->w;
if (x < 0)
x = 0;
}
else
x = g->x;
Epplet_textclass_draw("EPPLET_TEXT_LARGE", "normal",
g->general.parent->bg_pmap, x, g->y,
g->label);
}
ESYNC;
}
XSetWindowBackgroundPixmap(disp, g->general.parent->win,
g->general.parent->bg_pmap);
XClearWindow(disp, g->general.parent->win);
EXFreeGC(gc);
}
Epplet_gadget
Epplet_create_popup(void)
{
GadPopup *g;
XSetWindowAttributes attr;
g = malloc(sizeof(GadPopup));
g->general.type = E_POPUP;
g->general.parent = context_win;
g->general.visible = 0;
g->x = 0;
g->y = 0;
g->w = 5;
g->h = 5;
g->popbutton = NULL;
g->entry_num = 0;
g->entry = NULL;
g->changed = 1;
attr.backing_store = NotUseful;
attr.override_redirect = True;
attr.colormap = imlib_context_get_colormap();
attr.border_pixel = 0;
attr.background_pixel = 0;
attr.save_under = False;
attr.event_mask = ButtonPressMask | ButtonReleaseMask |
PointerMotionMask | EnterWindowMask | LeaveWindowMask | ButtonMotionMask;
g->win = XCreateWindow(disp, root, 0, 0, 5, 5, 0,
CopyFromParent, InputOutput, CopyFromParent,
CWOverrideRedirect | CWSaveUnder | CWBackingStore |
CWColormap | CWBackPixel | CWBorderPixel |
CWEventMask, &attr);
Epplet_add_gad((Epplet_gadget) g);
return (Epplet_gadget) g;
}
void
Epplet_add_popup_entry(Epplet_gadget gadget, const char *label,
const char *pixmap, void (*func)(void *data), void *data)
{
Epplet_add_sized_popup_entry(gadget, label, pixmap, -1, -1, func, data);
}
void
Epplet_add_sized_popup_entry(Epplet_gadget gadget, const char *label,
const char *pixmap, int w, int h,
void (*func)(void *data), void *data)
{
GadPopup *g;
g = (GadPopup *) gadget;
GADGET_CONFIRM_TYPE(gadget, E_POPUP);
g->entry_num++;
if (g->entry)
g->entry = realloc(g->entry, sizeof(*g->entry) * g->entry_num);
else
g->entry = malloc(sizeof(*g->entry));
g->entry[g->entry_num - 1].label = Estrdup(label);
g->entry[g->entry_num - 1].image = Estrdup(pixmap);
g->entry[g->entry_num - 1].w = 0;
g->entry[g->entry_num - 1].h = 0;
g->entry[g->entry_num - 1].func = func;
g->entry[g->entry_num - 1].data = data;
g->entry[g->entry_num - 1].gadget = NULL;
if (g->entry[g->entry_num - 1].image)
{
Imlib_Image *im;
im = imlib_load_image(g->entry[g->entry_num - 1].image);
imlib_context_set_image(im);
g->entry[g->entry_num - 1].w =
((w == -1) ? imlib_image_get_width() : w);
g->entry[g->entry_num - 1].h =
((h == -1) ? imlib_image_get_height() : h);
imlib_free_image();
}
else if (g->entry[g->entry_num - 1].label)
{
int tw, th;
Epplet_textclass_get_size("EPPLET_POPUP",
&tw, &th, g->entry[g->entry_num - 1].label);
g->entry[g->entry_num - 1].w = ((w == -1) ? tw : w);
g->entry[g->entry_num - 1].h = ((h == -1) ? th : h);
}
g->changed = 1;
}
void
Epplet_remove_popup_entry(Epplet_gadget gadget, int entry_num)
{
GadPopup *g;
int i;
g = (GadPopup *) gadget;
GADGET_CONFIRM_TYPE(gadget, E_POPUP);
if (!g->entry)
return;
if (entry_num < 0)
entry_num = g->entry_num + entry_num;
if (g->entry_num < entry_num)
return;
if (g->entry[entry_num].label)
{
free(g->entry[entry_num].label);
g->entry[entry_num].label = NULL;
}
if (g->entry[entry_num].image)
{
free(g->entry[entry_num].image);
g->entry[entry_num].image = NULL;
}
g->entry_num--;
for (i = entry_num; i < g->entry_num; i++)
{
*((g->entry) + i) = *((g->entry) + i + 1);
}
if (g->entry_num)
g->entry = realloc(g->entry, sizeof(GadPopup) * g->entry_num);
else
{
free(g->entry);
g->entry = NULL;
}
g->changed = 1;
}
void *
Epplet_popup_entry_get_data(Epplet_gadget gadget, int entry_num)
{
GadPopup *g;
/* int i; */
g = (GadPopup *) gadget;
GADGET_CONFIRM_TYPE_RVAL(gadget, E_POPUP, NULL);
if (!g->entry)
return NULL;
if (entry_num < 0)
entry_num = g->entry_num + entry_num;
if (g->entry_num < entry_num)
return NULL;
return ((g->entry)[entry_num]).data;
}
int
Epplet_popup_entry_num(Epplet_gadget gadget)
{
if (((GadGeneral *) gadget)->type == E_POPUP)
return ((GadPopup *) gadget)->entry_num;
else
return 0;
}
void
Epplet_popup_arrange_contents(Epplet_gadget gadget)
{
GadPopup *g;
int i, mw, mh, x, y;
g = (GadPopup *) gadget;
mw = 0;
mh = 0;
for (i = 0; i < g->entry_num; i++)
{
if (g->entry[i].w > mw)
mw = g->entry[i].w;
if (g->entry[i].h > mh)
mh = g->entry[i].h;
}
x = 0;
y = 0;
XResizeWindow(disp, g->win, mw + 8, ((mh + 4) * g->entry_num) + 4);
for (i = 0; i < g->entry_num; i++)
{
g->entry[i].gadget = Epplet_create_button(g->entry[i].label,
g->entry[i].image,
x + 2, y + 2,
mw + 4, mh + 4, NULL,
g->win, gadget,
g->entry[i].func,
g->entry[i].data);
Epplet_gadget_show(g->entry[i].gadget);
y += mh + 4;
}
g->x = 0;
g->y = 0;
g->w = mw + 8;
g->h = ((mh + 4) * g->entry_num) + 4;
XSync(disp, False);
}
void
Epplet_draw_popup(Epplet_gadget gadget)
{
GadPopup *g;
g = (GadPopup *) gadget;
if (g->changed)
{
g->changed = 0;
Epplet_imageclass_apply("EPPLET_POPUP_BASE", "normal", g->win);
}
}
void
Epplet_pop_popup(Epplet_gadget gadget, Window ww)
{
GadPopup *g;
g = (GadPopup *) gadget;
if (g->changed)
Epplet_popup_arrange_contents(gadget);
if (ww)
{
int px, py, rw, rh, x, y;
Window dw;
unsigned int w, h, b, d;
XGetGeometry(disp, root, &dw, &x, &y,
(unsigned int *)&rw, (unsigned int *)&rh, &b, &d);
XGetGeometry(disp, ww, &dw, &x, &y, &w, &h, &b, &d);
XTranslateCoordinates(disp, ww, root, 0, 0, &px, &py, &dw);
if ((py + ((int)h / 2)) > (rh / 2))
{
g->x = px + ((w - g->w) / 2);
g->y = py - g->h;
}
else
{
g->x = px + ((w - g->w) / 2);
g->y = py + h;
}
}
else
{
int rw, rh, rr, x, y;
Window dw;
unsigned int b, d;
XGetGeometry(disp, root, &dw, &x, &y,
(unsigned int *)&rw, (unsigned int *)&rh, &b, &d);
XQueryPointer(disp, root, &dw, &dw, &rr, &rr, &x, &y, &b);
g->x = x - (g->w / 2);
g->y = y - 8;
if (g->x < 0)
g->x = 0;
if (g->y < 0)
g->y = 0;
if ((g->x + g->w) > rw)
g->x = rw - g->w;
if ((g->y + g->h) > rh)
g->y = rh - g->h;
}
XMoveWindow(disp, g->win, g->x, g->y);
Epplet_gadget_show(gadget);
}
Epplet_gadget
Epplet_create_popupbutton(const char *label, const char *image, int x,
int y, int w, int h, const char *std,
Epplet_gadget popup)
{
GadPopupButton *g;
XSetWindowAttributes attr;
g = malloc(sizeof(GadPopupButton));
g->general.type = E_POPUPBUTTON;
g->general.parent = context_win;
g->x = x;
g->y = y;
g->std = Estrdup(std);
if (g->std)
{
g->w = 12;
g->h = 12;
}
else
{
g->w = w;
g->h = h;
}
g->pmap = 0;
g->mask = 0;
g->label = Estrdup(label);
g->image = Epplet_find_file(image);
g->hilited = 0;
g->clicked = 0;
g->popped = 0;
g->popup = popup;
attr.backing_store = NotUseful;
attr.override_redirect = False;
attr.colormap = imlib_context_get_colormap();
attr.border_pixel = 0;
attr.background_pixel = 0;
attr.save_under = False;
attr.event_mask = ButtonPressMask | ButtonReleaseMask |
EnterWindowMask | LeaveWindowMask;
g->general.visible = 0;
g->win = XCreateWindow(disp, context_win->win, x, y, g->w, g->h, 0,
CopyFromParent, InputOutput, CopyFromParent,
CWOverrideRedirect | CWSaveUnder | CWBackingStore |
CWColormap | CWBackPixel | CWBorderPixel |
CWEventMask, &attr);
XSaveContext(disp, g->win, xid_context, (XPointer) g);
Epplet_add_gad((Epplet_gadget) g);
return (Epplet_gadget) g;
}
void
Epplet_draw_popupbutton(Epplet_gadget eg)
{
GadPopupButton *g;
const char *state;
GADGET_CONFIRM_TYPE(eg, E_POPUPBUTTON);
g = (GadPopupButton *) eg;
if (g->hilited)
{
if (g->clicked)
state = "clicked";
else
state = "hilited";
}
else
{
if (g->clicked)
state = "clicked";
else
state = "normal";
}
if (g->popped)
state = "clicked";
if (g->pmap)
XFreePixmap(disp, g->pmap);
if (g->mask)
XFreePixmap(disp, g->mask);
g->pmap = 0;
g->mask = 0;
if (g->std)
{
char s[1024];
snprintf(s, sizeof(s), "EPPLET_%s", g->std);
Epplet_imageclass_get_pixmaps(s, state,
&(g->pmap), &(g->mask), g->w, g->h);
}
else
{
Epplet_imageclass_get_pixmaps("EPPLET_BUTTON", state,
&(g->pmap), &(g->mask), g->w, g->h);
if (g->image)
{
Imlib_Image *im;
ESYNC;
im = imlib_load_image(g->image);
if (im)
{
int x, y, w, h;
imlib_context_set_image(im);
if (g->w > imlib_image_get_width())
{
w = imlib_image_get_width();
x = (g->w - imlib_image_get_width()) / 2;
}
else
{
w = g->w - 4;
x = 2;
}
if (g->h > imlib_image_get_height())
{
h = imlib_image_get_height();
y = (g->h - imlib_image_get_height()) / 2;
}
else
{
h = g->h - 4;
y = 2;
}
imlib_context_set_drawable(g->pmap);
imlib_render_image_on_drawable_at_size(x, y, w, h);
imlib_free_image();
}
}
if (g->label)
{
int x, y, w, h;
Epplet_textclass_get_size("EPPLET_BUTTON", &w, &h, g->label);
x = (g->w - w) / 2;
y = (g->h - h) / 2;
Epplet_textclass_draw("EPPLET_BUTTON", state, g->pmap, x, y,
g->label);
}
}
ESYNC;
XSetWindowBackgroundPixmap(disp, g->win, g->pmap);
XShapeCombineMask(disp, g->win, ShapeBounding, 0, 0, g->mask, ShapeSet);
XClearWindow(disp, g->win);
}
void
Epplet_change_popbutton_popup(Epplet_gadget gadget, Epplet_gadget popup)
{
GadPopupButton *g;
GadGeneral *gg;
GADGET_CONFIRM_TYPE(gadget, E_POPUPBUTTON);
GADGET_CONFIRM_TYPE(popup, E_POPUP);
g = (GadPopupButton *) gadget;
gg = (GadGeneral *) gadget;
Epplet_gadget_destroy(g->popup);
g->popped = 0;
g->popup = popup;
if (gg->visible != 0)
Epplet_draw_popupbutton(gadget);
}
void
Epplet_change_popbutton_label(Epplet_gadget gadget, const char *label)
{
GadPopupButton *g;
GadGeneral *gg;
GADGET_CONFIRM_TYPE(gadget, E_POPUPBUTTON);
g = (GadPopupButton *) gadget;
gg = (GadGeneral *) gadget;
if (g->label)
{
if (label && !strcmp(g->label, label))
return; /* The labels are identical, so no sense in redrawing */
else
free(g->label); /* The labels are different. Proceed. */
}
g->label = Estrdup(label);
if (gg->visible != 0)
Epplet_draw_popupbutton(gadget);
}
void
Epplet_change_image(Epplet_gadget gadget, int w, int h, const char *image)
{
GadImage *g;
GadGeneral *gg;
GADGET_CONFIRM_TYPE(gadget, E_IMAGE);
g = (GadImage *) gadget;
gg = (GadGeneral *) gadget;
free(g->image);
g->image = Epplet_find_file(image);
g->w = w;
g->h = h;
if (gg->visible != 0)
Epplet_draw_image(gadget, 0);
}
void
Epplet_move_change_image(Epplet_gadget gadget, int x, int y, int w, int h,
const char *image)
{
GadImage *g;
GadGeneral *gg;
GADGET_CONFIRM_TYPE(gadget, E_IMAGE);
g = (GadImage *) gadget;
gg = (GadGeneral *) gadget;
Epplet_draw_image(gadget, 1);
free(g->image);
g->image = Epplet_find_file(image);
g->w = w;
g->h = h;
g->x = x;
g->y = y;
if (gg->visible != 0)
Epplet_draw_image(gadget, 0);
}
void
Epplet_change_label(Epplet_gadget gadget, const char *label)
{
GadLabel *g;
GadGeneral *gg;
GADGET_CONFIRM_TYPE(gadget, E_LABEL);
g = (GadLabel *) gadget;
gg = (GadGeneral *) gadget;
if (g->label)
{
if (label && !strcmp(g->label, label))
return; /* The labels are identical, so no sense in redrawing */
else
free(g->label); /* The labels are different. Proceed. */
}
g->label = Estrdup(label);
if (gg->visible != 0)
Epplet_draw_label(gadget, 0);
}
void
Epplet_move_change_label(Epplet_gadget gadget, int x, int y, const char *label)
{
GadLabel *g;
GadGeneral *gg;
GADGET_CONFIRM_TYPE(gadget, E_LABEL);
g = (GadLabel *) gadget;
gg = (GadGeneral *) gadget;
if (gg->visible)
Epplet_draw_label(gadget, 1);
if (g->label)
{
if (label && !strcmp(g->label, label))
return; /* The labels are identical, so no sense in redrawing */
else
free(g->label); /* The labels are different. Proceed. */
}
g->label = Estrdup(label);
g->x = x;
g->y = y;
if (gg->visible)
Epplet_draw_label(gadget, 0);
}
Window
Epplet_get_drawingarea_window(Epplet_gadget gadget)
{
GadDrawingArea *g;
GADGET_CONFIRM_TYPE_RVAL(gadget, E_DRAWINGAREA, None);
g = (GadDrawingArea *) gadget;
return g->win_in;
}
void
Epplet_event(Epplet_gadget gadget, XEvent * ev)
{
static int rx = 0, ry = 0, dx, dy;
GadGeneral *gg;
gg = (GadGeneral *) gadget;
switch (ev->type)
{
case KeyPress:
rx = ev->xbutton.x_root;
ry = ev->xbutton.y_root;
switch (gg->type)
{
case E_BUTTON:
break;
case E_TEXTBOX:
{
GadTextBox *g;
g = (GadTextBox *) gadget;
Epplet_textbox_handle_keyevent(ev, gadget);
Epplet_draw_textbox(g);
}
break;
case E_VSLIDER:
break;
case E_HSLIDER:
break;
case E_POPUPBUTTON:
break;
case E_DRAWINGAREA:
break;
case E_IMAGE:
break;
case E_LABEL:
break;
case E_VBAR:
break;
case E_HBAR:
break;
case E_TOGGLEBUTTON:
break;
case E_POPUP:
break;
}
break;
case ButtonPress:
rx = ev->xbutton.x_root;
ry = ev->xbutton.y_root;
switch (gg->type)
{
case E_BUTTON:
{
GadButton *g;
if (ev->xbutton.button > 3)
break;
g = (GadButton *) gadget;
g->clicked = 1;
Epplet_draw_button(gadget);
}
break;
case E_HSLIDER:
{
GadHSlider *g;
g = (GadHSlider *) gadget;
if (ev->xbutton.button < 4)
g->clicked = 1;
if (ev->xbutton.window == g->win)
{
if (ev->xbutton.button == 4)
(*(g->val)) += g->jump;
else if (ev->xbutton.button == 5)
(*(g->val)) -= g->jump;
else if (ev->xbutton.x > (((*(g->val)) * g->w) /
(g->max - g->min + 1)))
(*(g->val)) += g->jump;
else
(*(g->val)) -= g->jump;
if ((*(g->val)) < g->min)
(*(g->val)) = g->min;
if ((*(g->val)) > g->max)
(*(g->val)) = g->max;
}
if (g->func)
(*(g->func)) (g->data);
Epplet_draw_hslider(gadget);
}
break;
case E_VSLIDER:
{
GadVSlider *g;
g = (GadVSlider *) gadget;
if (ev->xbutton.button < 4)
g->clicked = 1;
if (ev->xbutton.window == g->win)
{
if (ev->xbutton.button == 4)
(*(g->val)) -= g->jump;
else if (ev->xbutton.button == 5)
(*(g->val)) += g->jump;
else if (ev->xbutton.y > (((*(g->val)) * g->h) /
(g->max - g->min + 1)))
(*(g->val)) += g->jump;
else
(*(g->val)) -= g->jump;
if ((*(g->val)) < g->min)
(*(g->val)) = g->min;
if ((*(g->val)) > g->max)
(*(g->val)) = g->max;
}
if (g->func)
(*(g->func)) (g->data);
Epplet_draw_vslider(gadget);
}
break;
case E_TOGGLEBUTTON:
{
GadToggleButton *g;
if (ev->xbutton.button > 3)
break;
g = (GadToggleButton *) gadget;
g->clicked = 1;
Epplet_draw_togglebutton(gadget);
}
break;
case E_POPUPBUTTON:
{
GadPopupButton *g;
if (ev->xbutton.button > 3)
break;
g = (GadPopupButton *) gadget;
g->clicked = 1;
Epplet_draw_popupbutton(gadget);
}
break;
case E_POPUP:
break;
case E_TEXTBOX:
{
GadTextBox *g;
int tmp_x, tmp_y, width, length, index,
last_index, text_w, text_h, text_wl, text_wr;
Window dummy;
char buf, left = 1, right = 1;
float delta;
g = (GadTextBox *) gadget;
if (!g->contents)
break;
XTranslateCoordinates(disp, g->win, root, 0, 0, &tmp_x, &tmp_y,
&dummy);
width = rx - tmp_x;
length = strlen(g->contents);
index = last_index = length / 2;
delta = last_index / 2;
Epplet_textbox_textsize(g, &text_w, &text_h, g->contents);
while (delta >= 1.0)
{
index = last_index;
buf = g->contents[index];
g->contents[index] = 0;
Epplet_textbox_textsize(g, &text_w, &text_h, g->contents);
g->contents[index] = buf;
if (text_w <= width)
last_index += rint(delta);
else
last_index -= rint(delta);
delta /= 2.0;
}
while (1)
{
if (left)
{
if (index <= 0)
break;
buf = g->contents[index - 1];
g->contents[index - 1] = 0;
Epplet_textbox_textsize(g, &text_wl, &text_h,
g->contents);
g->contents[index - 1] = buf;
}
if (right)
{
if (index >= length)
break;
buf = g->contents[index + 1];
g->contents[index + 1] = 0;
Epplet_textbox_textsize(g, &text_wr, &text_h,
g->contents);
g->contents[index + 1] = buf;
}
if (abs(text_wl - width) < abs(text_w - width))
{
right = 0;
text_wr = text_w;
text_w = text_wl;
index--;
}
else if (abs(text_wr - width) < abs(text_w - width))
{
left = 0;
text_wl = text_w;
text_w = text_wr;
index++;
}
else
break;
}
g->cursor_pos = index;
Epplet_draw_textbox(g);
}
break;
default:
break;
}
break;
case ButtonRelease:
rx = ev->xbutton.x_root;
ry = ev->xbutton.y_root;
switch (gg->type)
{
case E_BUTTON:
{
GadButton *g;
if (ev->xbutton.button > 3)
break;
g = (GadButton *) gadget;
g->clicked = 0;
Epplet_draw_button(gadget);
if (g->pop_parent)
Epplet_gadget_hide(g->pop_parent);
if ((g->hilited) && (g->func))
(*(g->func)) (g->data);
}
break;
case E_TEXTBOX:
{
GadTextBox *g;
char *s;
int nbytes_return;
g = (GadTextBox *) gadget;
if (ev->xbutton.button == 2)
{
s = XFetchBuffer(disp, &nbytes_return, 0);
if (nbytes_return)
Epplet_textbox_insert(g, s);
}
}
break;
case E_HSLIDER:
{
GadHSlider *g;
g = (GadHSlider *) gadget;
if (ev->xbutton.button < 4)
g->clicked = 0;
Epplet_draw_hslider(gadget);
}
break;
case E_VSLIDER:
{
GadVSlider *g;
g = (GadVSlider *) gadget;
if (ev->xbutton.button < 4)
g->clicked = 0;
Epplet_draw_vslider(gadget);
}
break;
case E_TOGGLEBUTTON:
{
GadToggleButton *g;
if (ev->xbutton.button > 3)
break;
g = (GadToggleButton *) gadget;
g->clicked = 0;
if (g->hilited)
{
if (*(g->val))
*(g->val) = 0;
else
*(g->val) = 1;
}
Epplet_draw_togglebutton(gadget);
if ((g->hilited) && (g->func))
(*(g->func)) (g->data);
}
break;
case E_POPUPBUTTON:
{
GadPopupButton *g;
if (ev->xbutton.button > 3)
break;
g = (GadPopupButton *) gadget;
g->clicked = 0;
if (g->popped)
{
if (g->popup)
Epplet_gadget_hide(g->popup);
}
else
{
if (g->popup)
{
Epplet_pop_popup(g->popup, g->win);
((GadPopup *) g->popup)->popbutton = gadget;
g->popped = 1;
}
Epplet_draw_popupbutton(gadget);
}
}
break;
case E_POPUP:
break;
default:
break;
}
break;
case MotionNotify:
dx = ev->xbutton.x_root - rx;
dy = ev->xbutton.y_root - ry;
rx = ev->xbutton.x_root;
ry = ev->xbutton.y_root;
switch (gg->type)
{
case E_HSLIDER:
{
GadHSlider *g;
int v, x, xx;
g = (GadHSlider *) gadget;
if (g->clicked)
{
x = ((g->w - 8) * (*(g->val))) / (g->max - g->min + 1);
xx = x + dx;
(*(g->val)) =
g->min + ((xx * (g->max - g->min)) / (g->w - 8));
v = (*(g->val)) / g->step;
if ((*(g->val)) - (v * g->step) >= (g->step / 2))
v++;
(*(g->val)) = v * g->step;
if ((*(g->val)) < g->min)
(*(g->val)) = g->min;
if ((*(g->val)) > g->max)
(*(g->val)) = g->max;
xx = ((g->w - 8) * (*(g->val))) / (g->max - g->min + 1);
rx = rx - dx + (xx - x);
if (g->func)
(*(g->func)) (g->data);
Epplet_draw_hslider(gadget);
}
}
break;
case E_VSLIDER:
{
GadVSlider *g;
int v, y, yy;
g = (GadVSlider *) gadget;
if (g->clicked)
{
y = ((g->h - 8) * (*(g->val))) / (g->max - g->min + 1);
yy = y + dy;
(*(g->val)) =
g->min + ((yy * (g->max - g->min)) / (g->h - 8));
v = (*(g->val)) / g->step;
if ((*(g->val)) - (v * g->step) >= (g->step / 2))
v++;
(*(g->val)) = v * g->step;
if ((*(g->val)) < g->min)
(*(g->val)) = g->min;
if ((*(g->val)) > g->max)
(*(g->val)) = g->max;
yy = ((g->h - 8) * (*(g->val))) / (g->max - g->min + 1);
ry = ry - dy + (yy - y);
if (g->func)
(*(g->func)) (g->data);
Epplet_draw_vslider(gadget);
}
}
break;
default:
break;
}
break;
case EnterNotify:
switch (gg->type)
{
case E_BUTTON:
{
GadButton *g;
g = (GadButton *) gadget;
g->hilited = 1;
Epplet_draw_button(gadget);
}
break;
case E_TEXTBOX:
{
GadTextBox *g;
g = (GadTextBox *) gadget;
g->hilited = 1;
Epplet_draw_textbox(gadget);
}
break;
case E_HSLIDER:
{
GadHSlider *g;
g = (GadHSlider *) gadget;
g->hilited = 1;
Epplet_draw_hslider(gadget);
}
break;
case E_VSLIDER:
{
GadVSlider *g;
g = (GadVSlider *) gadget;
g->hilited = 1;
Epplet_draw_vslider(gadget);
}
break;
case E_TOGGLEBUTTON:
{
GadToggleButton *g;
g = (GadToggleButton *) gadget;
g->hilited = 1;
Epplet_draw_togglebutton(gadget);
}
break;
case E_POPUPBUTTON:
{
GadPopupButton *g;
g = (GadPopupButton *) gadget;
g->hilited = 1;
Epplet_draw_popupbutton(gadget);
}
break;
case E_POPUP:
break;
default:
break;
}
break;
case LeaveNotify:
switch (gg->type)
{
case E_BUTTON:
{
GadButton *g;
g = (GadButton *) gadget;
g->hilited = 0;
Epplet_draw_button(gadget);
}
break;
case E_TEXTBOX:
{
GadTextBox *g;
g = (GadTextBox *) gadget;
g->hilited = 0;
Epplet_draw_textbox(gadget);
}
break;
case E_HSLIDER:
{
GadHSlider *g;
g = (GadHSlider *) gadget;
g->hilited = 0;
Epplet_draw_hslider(gadget);
}
break;
case E_VSLIDER:
{
GadVSlider *g;
g = (GadVSlider *) gadget;
g->hilited = 0;
Epplet_draw_vslider(gadget);
}
break;
case E_TOGGLEBUTTON:
{
GadToggleButton *g;
g = (GadToggleButton *) gadget;
g->hilited = 0;
Epplet_draw_togglebutton(gadget);
}
break;
case E_POPUPBUTTON:
{
GadPopupButton *g;
g = (GadPopupButton *) gadget;
g->hilited = 0;
Epplet_draw_popupbutton(gadget);
}
break;
case E_POPUP:
break;
default:
break;
}
break;
default:
break;
}
}
void
Epplet_background_properties(char vertical, Window newwin)
{
GC gc;
Epplet_window win;
win = Epplet_window_get_from_Window(newwin);
if (!win)
return;
if (win->bg_pmap)
XFreePixmap(disp, win->bg_pmap);
if (win->bg_bg)
XFreePixmap(disp, win->bg_bg);
if (win->bg_mask)
XFreePixmap(disp, win->bg_mask);
win->bg_pmap = 0;
win->bg_mask = 0;
win->bg_bg = 0;
if (vertical)
Epplet_imageclass_get_pixmaps("EPPLET_BACKGROUND_VERTICAL", "normal",
&win->bg_bg, &win->bg_mask, win->w, win->h);
else
Epplet_imageclass_get_pixmaps("EPPLET_BACKGROUND_HORIZONTAL", "normal",
&win->bg_bg, &win->bg_mask, win->w, win->h);
win->bg_pmap = XCreatePixmap(disp, win->win, win->w, win->h, DEPTH());
gc = EXCreateGC(win->bg_pmap);
XCopyArea(disp, win->bg_bg, win->bg_pmap, gc, 0, 0, win->w, win->h, 0, 0);
XSetWindowBackgroundPixmap(disp, win->win, win->bg_pmap);
XShapeCombineMask(disp, win->win, ShapeBounding, 0, 0, win->bg_mask,
ShapeSet);
XClearWindow(disp, win->win);
win->win_vert = vertical;
EXFreeGC(gc);
}
void
Epplet_gadget_destroy(Epplet_gadget gadget)
{
GadGeneral *gg;
Epplet_gadget_hide(gadget);
gg = (GadGeneral *) gadget;
Epplet_del_gad(gadget);
switch (gg->type)
{
case E_BUTTON:
{
GadButton *g;
g = (GadButton *) gadget;
XDestroyWindow(disp, g->win);
XDeleteContext(disp, g->win, xid_context);
free(g->label);
free(g->image);
free(g->std);
free(g);
}
break;
case E_DRAWINGAREA:
{
GadDrawingArea *g;
g = (GadDrawingArea *) gadget;
XDestroyWindow(disp, g->win);
free(g);
}
break;
case E_HSLIDER:
{
GadHSlider *g;
g = (GadHSlider *) gadget;
XDestroyWindow(disp, g->win);
XDestroyWindow(disp, g->win_knob);
XDeleteContext(disp, g->win, xid_context);
XDeleteContext(disp, g->win_knob, xid_context);
free(g);
}
break;
case E_VSLIDER:
{
GadVSlider *g;
g = (GadVSlider *) gadget;
XDestroyWindow(disp, g->win);
XDestroyWindow(disp, g->win_knob);
XDeleteContext(disp, g->win, xid_context);
XDeleteContext(disp, g->win_knob, xid_context);
free(g);
}
break;
case E_TOGGLEBUTTON:
{
GadToggleButton *g;
g = (GadToggleButton *) gadget;
XDestroyWindow(disp, g->win);
XDeleteContext(disp, g->win, xid_context);
free(g->label);
free(g->image);
free(g);
}
break;
case E_POPUPBUTTON:
{
GadPopupButton *g;
g = (GadPopupButton *) gadget;
XDestroyWindow(disp, g->win);
XDeleteContext(disp, g->win, xid_context);
free(g->std);
free(g->label);
free(g->image);
free(g);
}
break;
case E_POPUP:
{
GadPopup *g;
int i;
g = (GadPopup *) gadget;
for (i = 0; i < g->entry_num; i++)
{
free(g->entry[i].label);
free(g->entry[i].image);
if (g->entry[i].gadget)
Epplet_gadget_destroy(g->entry[i].gadget);
}
free(g->entry);
XDestroyWindow(disp, g->win);
XDeleteContext(disp, g->win, xid_context);
free(g);
}
break;
case E_IMAGE:
{
GadImage *g;
g = (GadImage *) gadget;
free(g->image);
free(g);
}
break;
case E_LABEL:
{
GadLabel *g;
g = (GadLabel *) gadget;
free(g->label);
free(g);
}
break;
case E_HBAR:
{
GadHBar *g;
g = (GadHBar *) gadget;
XDestroyWindow(disp, g->win);
free(g);
}
break;
case E_VBAR:
{
GadVBar *g;
g = (GadVBar *) gadget;
XDestroyWindow(disp, g->win);
free(g);
}
break;
default:
break;
}
}
void
Epplet_gadget_hide(Epplet_gadget gadget)
{
GadGeneral *gg;
gg = (GadGeneral *) gadget;
if (!(gg->visible))
return;
gg->visible = 0;
switch (gg->type)
{
case E_BUTTON:
{
GadButton *g;
g = (GadButton *) gadget;
XUnmapWindow(disp, g->win);
}
break;
case E_TEXTBOX:
{
GadTextBox *g;
g = (GadTextBox *) gadget;
XUnmapWindow(disp, g->win);
}
break;
case E_DRAWINGAREA:
{
GadDrawingArea *g;
g = (GadDrawingArea *) gadget;
XUnmapWindow(disp, g->win);
}
break;
case E_HSLIDER:
{
GadHSlider *g;
g = (GadHSlider *) gadget;
XUnmapWindow(disp, g->win);
XUnmapWindow(disp, g->win_knob);
}
break;
case E_VSLIDER:
{
GadVSlider *g;
g = (GadVSlider *) gadget;
XUnmapWindow(disp, g->win);
XUnmapWindow(disp, g->win_knob);
}
break;
case E_TOGGLEBUTTON:
{
GadToggleButton *g;
g = (GadToggleButton *) gadget;
XUnmapWindow(disp, g->win);
}
break;
case E_POPUPBUTTON:
{
GadPopupButton *g;
g = (GadPopupButton *) gadget;
XUnmapWindow(disp, g->win);
}
break;
case E_POPUP:
{
GadPopup *g;
g = (GadPopup *) gadget;
XUnmapWindow(disp, g->win);
if (g->popbutton)
{
((GadPopupButton *) g->popbutton)->popped = 0;
Epplet_draw_popupbutton(g->popbutton);
g->popbutton = NULL;
}
}
break;
case E_IMAGE:
{
Epplet_draw_image(gadget, 1);
}
break;
case E_LABEL:
{
Epplet_draw_label(gadget, 1);
}
break;
case E_HBAR:
{
GadHBar *g;
g = (GadHBar *) gadget;
XUnmapWindow(disp, g->win);
}
break;
case E_VBAR:
{
GadVBar *g;
g = (GadVBar *) gadget;
XUnmapWindow(disp, g->win);
}
break;
default:
break;
}
}
void
Epplet_gadget_show(Epplet_gadget gadget)
{
GadGeneral *gg;
gg = (GadGeneral *) gadget;
if (gg->visible)
return;
gg->visible = 1;
if (!epplet_visible)
return;
switch (gg->type)
{
case E_BUTTON:
{
GadButton *g;
g = (GadButton *) gadget;
Epplet_draw_button(gadget);
XMapWindow(disp, g->win);
}
break;
case E_TEXTBOX:
{
GadTextBox *g;
g = (GadTextBox *) gadget;
Epplet_draw_textbox(gadget);
XMapWindow(disp, g->win);
}
break;
case E_DRAWINGAREA:
{
GadDrawingArea *g;
g = (GadDrawingArea *) gadget;
Epplet_draw_drawingarea(gadget);
XMapWindow(disp, g->win);
}
break;
case E_HSLIDER:
{
GadHSlider *g;
g = (GadHSlider *) gadget;
Epplet_draw_hslider(gadget);
XMapWindow(disp, g->win);
XMapRaised(disp, g->win_knob);
}
break;
case E_VSLIDER:
{
GadVSlider *g;
g = (GadVSlider *) gadget;
Epplet_draw_vslider(gadget);
XMapWindow(disp, g->win);
XMapRaised(disp, g->win_knob);
}
break;
case E_TOGGLEBUTTON:
{
GadToggleButton *g;
g = (GadToggleButton *) gadget;
Epplet_draw_togglebutton(gadget);
XMapWindow(disp, g->win);
}
break;
case E_POPUPBUTTON:
{
GadPopupButton *g;
g = (GadPopupButton *) gadget;
Epplet_draw_popupbutton(gadget);
XMapWindow(disp, g->win);
}
break;
case E_POPUP:
{
GadPopup *g;
g = (GadPopup *) gadget;
Epplet_popup_arrange_contents(gadget);
Epplet_draw_popup(gadget);
XMapRaised(disp, g->win);
}
break;
case E_IMAGE:
{
Epplet_draw_image(gadget, 0);
}
break;
case E_LABEL:
{
Epplet_draw_label(gadget, 0);
}
break;
case E_HBAR:
{
GadHBar *g;
g = (GadHBar *) gadget;
Epplet_draw_hbar(gadget);
XMapWindow(disp, g->win);
}
break;
case E_VBAR:
{
GadVBar *g;
g = (GadVBar *) gadget;
Epplet_draw_vbar(gadget);
XMapWindow(disp, g->win);
}
break;
default:
break;
}
}
void
Epplet_gadget_move(Epplet_gadget gadget, int x, int y)
{
GadImage *g; /* Image is the lowest common denominator, sorta. */
g = (GadImage *) gadget;
Epplet_gadget_draw(gadget, 1, 0);
g->x = x;
g->y = y;
if (g->win != None)
{
XMoveWindow(disp, g->win, x, y);
}
Epplet_gadget_draw(gadget, 0, 0);
}
void *
Epplet_gadget_get_data(Epplet_gadget gadget)
{
if (!gadget)
return NULL;
switch (((GadGeneral *) gadget)->type)
{
case E_BUTTON:
return ((GadButton *) gadget)->data;
case E_TOGGLEBUTTON:
return ((GadToggleButton *) gadget)->data;
case E_HSLIDER:
return ((GadHSlider *) gadget)->data;
case E_VSLIDER:
return ((GadVSlider *) gadget)->data;
default:
return NULL;
}
}
void
Epplet_gadget_data_changed(Epplet_gadget gadget)
{
GadGeneral *gg;
gg = (GadGeneral *) gadget;
if (!gg->visible)
return;
switch (gg->type)
{
case E_HSLIDER:
Epplet_draw_hslider(gadget);
break;
case E_VSLIDER:
Epplet_draw_vslider(gadget);
break;
case E_TOGGLEBUTTON:
Epplet_draw_togglebutton(gadget);
break;
case E_IMAGE:
Epplet_draw_image(gadget, 0);
break;
case E_LABEL:
Epplet_draw_label(gadget, 0);
break;
case E_HBAR:
Epplet_draw_hbar(gadget);
break;
case E_VBAR:
Epplet_draw_vbar(gadget);
break;
default:
break;
}
}
void
Epplet_gadget_draw(Epplet_gadget g, int un_only, int force)
{
GadGeneral *gg = (GadGeneral *) g;
if (gg->visible || force)
{
switch (gg->type)
{
case E_BUTTON:
if (!un_only)
Epplet_draw_button(g);
break;
case E_TEXTBOX:
if (!un_only)
Epplet_draw_textbox(g);
break;
case E_DRAWINGAREA:
if (!un_only)
Epplet_draw_drawingarea(g);
break;
case E_HSLIDER:
if (!un_only)
Epplet_draw_hslider(g);
break;
case E_VSLIDER:
if (!un_only)
Epplet_draw_vslider(g);
break;
case E_TOGGLEBUTTON:
if (!un_only)
Epplet_draw_togglebutton(g);
break;
case E_POPUPBUTTON:
if (!un_only)
Epplet_draw_popupbutton(g);
break;
case E_POPUP:
if (!un_only)
Epplet_draw_popup(g);
break;
case E_IMAGE:
Epplet_draw_image(g, un_only);
break;
case E_LABEL:
Epplet_draw_label(g, un_only);
break;
case E_HBAR:
if (!un_only)
Epplet_draw_hbar(g);
break;
case E_VBAR:
if (!un_only)
Epplet_draw_vbar(g);
break;
default:
break;
}
}
}
void
Epplet_redraw(void)
{
int i;
GadGeneral *gg;
Epplet_refresh_backgrounds();
for (i = 0; i < gad_num; i++)
{
gg = (GadGeneral *) gads[i];
if (gg->visible)
{
gg->visible = 0;
Epplet_gadget_show(gads[i]);
}
}
}
void
Esync(void)
{
XSync(disp, False);
}
void
Epplet_draw_line(Window win, int x1, int y1, int x2, int y2,
int r, int g, int b)
{
static int cr = -1, cg = -1, cb = -1;
GC gc;
gc = EXCreateGC(win);
if ((cr != r) || (cg != g) || (cb != b))
XSetForeground(disp, gc, Epplet_get_color(r, g, b));
XDrawLine(disp, win, gc, x1, y1, x2, y2);
EXFreeGC(gc);
}
void
Epplet_draw_box(Window win, int x, int y, int w, int h, int r, int g, int b)
{
static int cr = -1, cg = -1, cb = -1;
GC gc;
if ((w <= 0) || (h <= 0))
return;
gc = EXCreateGC(win);
if ((cr != r) || (cg != g) || (cb != b))
XSetForeground(disp, gc, Epplet_get_color(r, g, b));
XFillRectangle(disp, win, gc, x, y, (unsigned int)w, (unsigned int)h);
EXFreeGC(gc);
}
void
Epplet_draw_outline(Window win, int x, int y, int w, int h, int r, int g, int b)
{
static int cr = -1, cg = -1, cb = -1;
GC gc;
if ((w <= 0) || (h <= 0))
return;
gc = EXCreateGC(win);
if ((cr != r) || (cg != g) || (cb != b))
XSetForeground(disp, gc, Epplet_get_color(r, g, b));
XDrawRectangle(disp, win, gc, x, y, (unsigned int)(w - 1),
(unsigned int)(h - 1));
EXFreeGC(gc);
}
RGB_buf
Epplet_make_rgb_buf(int w, int h)
{
RGB_buf buf;
buf = malloc(sizeof(RGB_buf));
buf->im = imlib_create_image(w, h);
return buf;
}
unsigned char *
Epplet_get_rgb_pointer(RGB_buf buf)
{
imlib_context_set_image(buf->im);
return (unsigned char *)imlib_image_get_data(); /* Readonly? */
}
void
Epplet_paste_buf(RGB_buf buf, Window win, int x, int y)
{
imlib_context_set_image(buf->im);
imlib_context_set_drawable(win);
imlib_render_image_on_drawable(x, y);
}
void
Epplet_free_rgb_buf(RGB_buf buf)
{
if (buf)
{
if (buf->im)
{
imlib_context_set_image(buf->im);
imlib_free_image();
}
free(buf);
}
}
static void
Epplet_handle_child(int num __UNUSED__)
{
int status;
pid_t pid;
while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
{
if (WIFEXITED(status))
{
int code;
code = WEXITSTATUS(status);
if (child_func)
(*child_func) (child_data, pid, code);
}
}
}
int
Epplet_run_command(const char *cmd)
{
return system(cmd);
}
const char *
Epplet_read_run_command(const char *cmd)
{
return cmd;
}
int
Epplet_spawn_command(const char *cmd)
{
pid_t pid;
pid = fork();
if (pid)
return (int)pid;
execl("/bin/sh", "/bin/sh", "-c", cmd, NULL);
exit(0);
}
void
Epplet_pause_spawned_command(int pid)
{
kill((pid_t) pid, SIGSTOP);
}
void
Epplet_unpause_spawned_command(int pid)
{
kill((pid_t) pid, SIGCONT);
}
void
Epplet_kill_spawned_command(int pid)
{
kill((pid_t) pid, SIGINT);
}
void
Epplet_destroy_spawned_command(int pid)
{
kill((pid_t) pid, SIGKILL);
}
void
Epplet_register_child_handler(void (*func)
(void *data, int pid, int exit_code), void *data)
{
child_data = data;
child_func = func;
}
void
Epplet_change_button_label(Epplet_gadget gadget, const char *label)
{
GadButton *g;
GadGeneral *gg;
GADGET_CONFIRM_TYPE(gadget, E_BUTTON);
g = (GadButton *) gadget;
gg = (GadGeneral *) gadget;
free(g->label);
g->label = Estrdup(label);
if (gg->visible)
Epplet_draw_button(gadget);
}
void
Epplet_change_button_image(Epplet_gadget gadget, const char *image)
{
GadButton *g;
GadGeneral *gg;
GADGET_CONFIRM_TYPE(gadget, E_BUTTON);
g = (GadButton *) gadget;
gg = (GadGeneral *) gadget;
free(g->image);
g->image = Epplet_find_file(image);
if (gg->visible)
Epplet_draw_button(gadget);
}
void
Epplet_clear_window(Window ww)
{
XClearWindow(disp, ww);
}
void
Epplet_show_about(const char *name __UNUSED__)
{
char s[1024];
snprintf(s, sizeof(s), "edox %s/ABOUT", Epplet_data_dir());
Epplet_spawn_command(s);
}
void
Epplet_dialog_ok(const char *fmt, ...)
{
va_list args;
char buf[1000];
va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
if (!dd)
{
printf("*** %s\n", buf);
return;
}
Epplet_send_ipc("dialog_ok %s", buf);
}
static void
Epplet_find_instance(const char *name)
{
struct stat st;
struct flock fl;
char s[1024];
int i, fd, err, exists, locked;
pid_t pid;
/* Set epplet data dir */
snprintf(s, sizeof(s), ENLIGHTENMENT_ROOT "/epplet_data/%s", name);
data_dir = Estrdup(s);
/* Find E dir */
snprintf(s, sizeof(s), "%s/.e16", getenv("HOME"));
if (stat(s, &st) < 0)
{
snprintf(s, sizeof(s), "%s/.enlightenment", getenv("HOME"));
if (stat(s, &st) < 0)
{
snprintf(s, sizeof(s), "%s/.enlightenment", getenv("HOME"));
mkdir(s, S_IRWXU);
}
}
e16_user_dir = strdup(s);
/* make sure basic dir exists */
snprintf(s, sizeof(s), "%s/epplet_config", Epplet_e16_user_dir());
if (stat(s, &st) < 0)
{
if (mkdir(s, S_IRWXU) < 0)
{
Epplet_dialog_ok
("Unable to create epplet config directory %s -- %s.\n",
s, strerror(errno));
epplet_instance = 1;
return;
}
}
/* make sure this epplet's config dir exists */
snprintf(s, sizeof(s), "%s/epplet_config/%s", Epplet_e16_user_dir(), name);
conf_dir = strdup(s);
if (stat(s, &st) < 0)
{
if (mkdir(s, S_IRWXU) < 0)
{
Epplet_dialog_ok
("Unable to create epplet config directory %s -- %s.\n",
s, strerror(errno));
epplet_instance = 1;
return;
}
}
/* Pick our instance number. 255 is the max to avoid infinite loops, which could be caused by
* lack of insert permissions in the config directory. */
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
fl.l_start = fl.l_len = 0;
locked = 0;
for (i = 1; i < 256; i++)
{
snprintf(s, sizeof(s), "%s/.lock_%i", conf_dir, i);
exists = stat(s, &st) == 0;
if (exists)
fd = open(s, (O_RDWR | O_CREAT), 0600);
else
fd = open(s, (O_WRONLY | O_EXCL | O_CREAT), 0600);
if (fd < 0)
continue;
for (;;)
{
err = fcntl(fd, F_SETLK, &fl);
if (err == 0 || errno != EINTR)
break;
}
if (err == 0)
{
/* Locking succeeded, file is open for writing */
locked = 1;
break;
}
if (errno == EACCES || errno == EAGAIN)
{
/* Locking failed due to held lock */
continue;
}
if (!exists)
{
/* Locking failed, but file was successfully created with O_EXCL */
break;
}
/* Check pid */
if ((read(fd, &pid, sizeof(pid_t))) < ((int)sizeof(pid_t)))
{
/* We didn't get enough bytes. Next! */
fprintf(stderr,
"Read attempt for lock file %s failed -- %s\n", s,
strerror(errno));
close(fd);
continue;
}
close(fd);
if (pid <= 0)
{
/* We got a bogus process ID. Next! */
fprintf(stderr,
"Lock file %s contained a bogus process ID (%lu)\n",
s, (unsigned long)pid);
continue;
}
if ((kill(pid, 0) == 0) || (errno != ESRCH))
{
/* The process exists. Next! */
continue;
}
/* Okay, looks like a stale lockfile at this point. Remove it. */
if ((unlink(s)) != 0)
{
/* Removal failed. Next! */
fprintf(stderr,
"Unable to remove stale lock file %s -- %s. Please remove it manually.\n",
s, strerror(errno));
continue;
}
srand(getpid());
usleep((rand() & 0xfffff));
if ((fd = open(s, (O_WRONLY | O_EXCL | O_CREAT), 0600)) < 0)
{
/* Apparently another process just came in under us and created it. Next! */
continue;
}
/* If we made it here, we've just created the lock file. We have our instance
* number, so exit the loop. */
break;
}
if (i < 256)
{
pid = getpid();
write(fd, &pid, sizeof(pid_t)); /* Not sure how best to deal with write errors here */
/* If locked do not close fd, otherwise lock is lost */
if (!locked)
close(fd);
}
else
{
i = 1;
}
epplet_instance = i;
/* find out epplet's name */
if (epplet_instance > 1)
{
snprintf(s, sizeof(s), "%s-%i", name, epplet_instance);
epplet_name = strdup(s);
}
else
epplet_name = strdup(name);
}
int
Epplet_get_instance(void)
{
return epplet_instance;
}
const char *
Epplet_data_dir(void)
{
return data_dir;
}
const char *
Epplet_e16_user_dir(void)
{
return e16_user_dir;
}
void
Epplet_load_config_file(const char *file)
{
char s[1024], s2[1024], s3[1024];
FILE *f = NULL;
if (config_dict)
Epplet_clear_config();
config_dict = calloc(1, sizeof(ConfigDict));
config_dict->entries = malloc(sizeof(ConfigItem));
if (!(f = fopen(file, "r")))
return;
for (; fgets(s, sizeof(s), f);)
{
s2[0] = s3[0] = '\0';
sscanf(s, "%s %[^\n]\n", s2, s3);
if (!(*s2) || (!*s3) || (*s2 == '\n') || (*s2 == '#'))
{
continue;
}
Epplet_add_config(s2, s3);
}
fclose(f);
}
void
Epplet_load_config(void)
{
char s[1024];
/* If they haven't initialized, abort */
if (epplet_instance == 0)
return;
if (!epplet_cfg_file)
{
/* create config file name */
snprintf(s, sizeof(s), "%s/%s.cfg", conf_dir, epplet_name);
epplet_cfg_file = strdup(s);
}
Epplet_load_config_file(epplet_cfg_file);
}
void
Epplet_save_config(void)
{
FILE *f;
int i;
if (!(config_dict) || (config_dict->num_entries <= 0))
return;
if (!(f = fopen(epplet_cfg_file, "w")))
{
Epplet_dialog_ok("Unable to write to config file %s -- %s.\n",
epplet_cfg_file, strerror(errno));
return;
}
fprintf(f, "### Automatically generated Epplet config file for %s.\n\n",
epplet_name);
for (i = 0; i < config_dict->num_entries; i++)
{
if (config_dict->entries[i].key && *(config_dict->entries[i].value))
{
fprintf(f, "%s %s\n", config_dict->entries[i].key,
config_dict->entries[i].value);
}
}
fclose(f);
}
void
Epplet_clear_config(void)
{
int i;
ConfigItem *ci;
for (i = 0; i < config_dict->num_entries; i++)
{
ci = &(config_dict->entries[i]);
free(ci->key);
free(ci->value);
}
free(config_dict->entries);
free(config_dict);
config_dict = NULL;
}
void
Epplet_add_config(const char *key, const char *value)
{
if (!key)
return;
if (!config_dict)
{
config_dict = calloc(1, sizeof(ConfigDict));
config_dict->entries = malloc(sizeof(ConfigItem));
}
else
{
config_dict->entries =
realloc(config_dict->entries,
sizeof(ConfigItem) * (config_dict->num_entries + 1));
}
config_dict->entries[config_dict->num_entries].key = strdup(key);
config_dict->entries[config_dict->num_entries].value =
(value ? strdup(value) : strdup(""));
config_dict->num_entries++;
}
const char *
Epplet_query_config(const char *key)
{
int i;
ConfigItem *ci;
if (!key)
return NULL;
for (i = 0; i < config_dict->num_entries; i++)
{
ci = &(config_dict->entries[i]);
if ((ci->key) && !strcmp(key, ci->key))
/* we've found the key */
return (ci->value);
}
return NULL;
}
const char *
Epplet_query_config_def(const char *key, const char *def)
{
int i;
ConfigItem *ci;
if (!key)
return def;
for (i = 0; i < config_dict->num_entries; i++)
{
ci = &(config_dict->entries[i]);
if ((ci->key) && !strcmp(key, ci->key))
/* we've found the key */
return (ci->value);
}
Epplet_add_config(key, def); /* Not found. Add the default. */
return def;
}
void
Epplet_modify_config(const char *key, const char *value)
{
int i;
ConfigItem *ci;
if (!key)
return;
for (i = 0; i < config_dict->num_entries; i++)
{
ci = &(config_dict->entries[i]);
if ((ci->key) && !strcmp(key, ci->key))
/* we've found the key */
{
if (ci->value != value)
{
free(ci->value);
if (value)
{
ci->value = strdup(value);
}
else
{
ci->value = strdup("");
}
}
return;
}
}
/* so we couldn't find the key, thus add it ... */
Epplet_add_config(key, value);
}
void
Epplet_modify_multi_config(const char *shortkey, char **values, int num)
{
int i, j, k, matches;
char key[64], key2[80];
char *s;
if (!shortkey)
return;
/* build the actual key: */
snprintf(key, sizeof(key), "__%s__", shortkey);
matches = 0;
/* first wipe out old ones */
for (i = 0; i < config_dict->num_entries; i++)
{
if (config_dict->entries[i].key)
{
s = strstr(config_dict->entries[i].key, key);
if (s == config_dict->entries[i].key)
/* we've found a key matching at the beginning */
{
/* check how many keys match (in a row) */
for (j = i + 1; j < config_dict->num_entries; j++)
{
s = strstr(config_dict->entries[i].key, key);
if (s != config_dict->entries[i].key)
break;
}
/* free their pointers */
matches = j - i;
for (k = i; k < j; k++)
{
free(config_dict->entries[k].key);
free(config_dict->entries[k].value);
}
/* and move the rest. */
for (k = 0; k < config_dict->num_entries - j; k++)
{
config_dict->entries[i + k] =
config_dict->entries[j + k];
}
break;
}
}
}
/* then insert new ones */
config_dict->entries = realloc(config_dict->entries,
sizeof(ConfigItem) *
(config_dict->num_entries - matches + num));
for (i = 0, j = config_dict->num_entries - matches; i < num; i++, j++)
{
snprintf(key2, sizeof(key2), "%s%i", key, i);
config_dict->entries[j].key = strdup(key2);
config_dict->entries[j].value = strdup(values[i]);
}
config_dict->num_entries = config_dict->num_entries - matches + num;
}
char **
Epplet_query_multi_config(const char *shortkey, int *num)
{
char **result = NULL;
char *s;
char key[64];
int i, j, k;
if (!shortkey)
return NULL;
/* build the actual key: */
snprintf(key, sizeof(key), "__%s__", shortkey);
*num = 0;
for (i = 0; i < config_dict->num_entries; i++)
{
if (config_dict->entries[i].key)
{
s = strstr(config_dict->entries[i].key, key);
if (s == config_dict->entries[i].key)
/* we've found a key matching at the beginning */
{
/* check how many keys match (in a row) */
for (j = i + 1, (*num) = 1; j < config_dict->num_entries;
j++, (*num)++)
{
s = strstr(config_dict->entries[j].key, key);
if (s != config_dict->entries[j].key)
break;
}
/* and build result */
result = malloc(sizeof(char *) * (*num));
if (result)
{
for (k = 0; k < (*num); k++)
{
result[k] = config_dict->entries[i + k].value;
}
return result;
}
*num = 0;
return NULL;
}
}
}
*num = 0;
return NULL;
}
int
Epplet_get_hslider_clicked(Epplet_gadget gadget)
{
GadHSlider *g;
GADGET_CONFIRM_TYPE_RVAL(gadget, E_HSLIDER, -1);
g = (GadHSlider *) gadget;
return (int)g->clicked;
}
int
Epplet_get_vslider_clicked(Epplet_gadget gadget)
{
GadVSlider *g;
GADGET_CONFIRM_TYPE_RVAL(gadget, E_VSLIDER, -1);
g = (GadVSlider *) gadget;
return (int)g->clicked;
}