1117 lines
39 KiB
C
1117 lines
39 KiB
C
/*
|
|
* 0BSD
|
|
*
|
|
* BSD Zero Clause License
|
|
*
|
|
* Copyright (c) 2019 Hermann Meyer
|
|
*
|
|
* Permission to use, copy, modify, and/or distribute this software for any
|
|
* purpose with or without fee is hereby granted.
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
* PERFORMANCE OF THIS SOFTWARE.
|
|
*
|
|
*/
|
|
|
|
|
|
#include "xwidget.h"
|
|
#include "xwidget_private.h"
|
|
|
|
|
|
int (*default_error_handler) (Display *dpy, XErrorEvent *e);
|
|
|
|
int intern_error_handler(Display *dpy, XErrorEvent *e) {
|
|
return 0;
|
|
}
|
|
|
|
int key_mapping(Display *dpy, XKeyEvent *xkey) {
|
|
if (xkey->keycode == XKeysymToKeycode(dpy,XK_Tab))
|
|
return (xkey->state & ShiftMask) ? 1 : 2;
|
|
else if (xkey->keycode == XKeysymToKeycode(dpy,XK_Up))
|
|
return 3;
|
|
else if (xkey->keycode == XKeysymToKeycode(dpy,XK_Right))
|
|
return 4;
|
|
else if (xkey->keycode == XKeysymToKeycode(dpy,XK_Down))
|
|
return 5;
|
|
else if (xkey->keycode == XKeysymToKeycode(dpy,XK_Left))
|
|
return 6;
|
|
else if (xkey->keycode == XKeysymToKeycode(dpy,XK_Home))
|
|
return 7;
|
|
else if (xkey->keycode == XKeysymToKeycode(dpy,XK_Insert))
|
|
return 8;
|
|
else if (xkey->keycode == XKeysymToKeycode(dpy,XK_End))
|
|
return 9;
|
|
else if (xkey->keycode == XKeysymToKeycode(dpy,XK_Return))
|
|
return 10;
|
|
else if (xkey->keycode == XKeysymToKeycode(dpy,XK_BackSpace))
|
|
return 11;
|
|
else if (xkey->keycode == XKeysymToKeycode(dpy,XK_Delete))
|
|
return 12;
|
|
// keypad
|
|
else if (xkey->keycode == XKeysymToKeycode(dpy,XK_KP_Subtract))
|
|
return 1;
|
|
else if (xkey->keycode == XKeysymToKeycode(dpy,XK_KP_Add))
|
|
return 2;
|
|
else if (xkey->keycode == XKeysymToKeycode(dpy,XK_KP_Up))
|
|
return 3;
|
|
else if (xkey->keycode == XKeysymToKeycode(dpy,XK_KP_Right))
|
|
return 4;
|
|
else if (xkey->keycode == XKeysymToKeycode(dpy,XK_KP_Down))
|
|
return 5;
|
|
else if (xkey->keycode == XKeysymToKeycode(dpy,XK_KP_Left))
|
|
return 6;
|
|
else if (xkey->keycode == XKeysymToKeycode(dpy,XK_KP_Home))
|
|
return 7;
|
|
else if (xkey->keycode == XKeysymToKeycode(dpy,XK_KP_Insert))
|
|
return 8;
|
|
else if (xkey->keycode == XKeysymToKeycode(dpy,XK_KP_End))
|
|
return 9;
|
|
else if (xkey->keycode == XKeysymToKeycode(dpy,XK_KP_Enter))
|
|
return 10;
|
|
else if (xkey->keycode == XKeysymToKeycode(dpy,XK_KP_Delete))
|
|
return 12;
|
|
else return 0;
|
|
}
|
|
|
|
void destroy_widget(Widget_t * w, Xputty *main) {
|
|
int count = childlist_find_child(main->childlist, w);
|
|
if (count == 0 && main->run == true) {
|
|
quit(w);
|
|
} else if(childlist_find_child(main->childlist, w)>=0) {
|
|
if(w->flags & REUSE_IMAGE) {
|
|
w->image = NULL;
|
|
}
|
|
if(w->flags & HAS_MEM) {
|
|
w->func.mem_free_callback(w, NULL);
|
|
}
|
|
childlist_remove_child(main->childlist, w);
|
|
int ch = childlist_has_child(w->childlist);
|
|
if (ch) {
|
|
int i = ch;
|
|
for(;i>0;i--) {
|
|
destroy_widget(w->childlist->childs[i-1],main);
|
|
|
|
}
|
|
destroy_widget(w,main);
|
|
}
|
|
if(w->flags & IS_WIDGET) {
|
|
Widget_t *p = (Widget_t *) w->parent;
|
|
childlist_remove_child(p->childlist, w);
|
|
}
|
|
delete_adjustment(w->adj_x);
|
|
delete_adjustment(w->adj_y);
|
|
childlist_destroy(w->childlist);
|
|
cairo_surface_destroy(w->image);
|
|
cairo_destroy(w->crb);
|
|
cairo_surface_destroy(w->buffer);
|
|
cairo_destroy(w->cr);
|
|
cairo_surface_destroy(w->surface);
|
|
|
|
XDestroyIC(w->xic);
|
|
XCloseIM(w->xim);
|
|
XUnmapWindow(w->app->dpy, w->widget);
|
|
XDestroyWindow(w->app->dpy, w->widget);
|
|
free(w->color_scheme);
|
|
free(w->childlist);
|
|
free(w);
|
|
w = NULL;
|
|
}
|
|
}
|
|
|
|
void configure_event(void *w_, void* user_data) {
|
|
Widget_t *wid = (Widget_t*)w_;
|
|
XWindowAttributes attrs;
|
|
XGetWindowAttributes(wid->app->dpy, (Window)wid->widget, &attrs);
|
|
if (wid->width != attrs.width || wid->height != attrs.height) {
|
|
wid->scale.scale_x = (float)wid->scale.init_width - attrs.width;
|
|
wid->scale.scale_y = (float)wid->scale.init_height - attrs.height;
|
|
wid->scale.cscale_x = (float)((float)wid->scale.init_width/(float)attrs.width);
|
|
wid->scale.cscale_y = (float)((float)wid->scale.init_height/(float)attrs.height);
|
|
wid->scale.rcscale_x = (float)((float)attrs.width/(float)wid->scale.init_width);
|
|
wid->scale.rcscale_y = (float)((float)attrs.height/(float)wid->scale.init_height);
|
|
wid->scale.ascale = wid->scale.cscale_x < wid->scale.cscale_y ?
|
|
wid->scale.cscale_y : wid->scale.cscale_x;
|
|
|
|
_resize_surface(wid, attrs.width, attrs.height);
|
|
|
|
debug_print("Widget_t configure callback width %i height %i\n", attrs.width, attrs.height);
|
|
|
|
_resize_childs(wid);
|
|
}
|
|
wid->func.configure_notify_callback(wid,NULL);
|
|
}
|
|
|
|
void resize_childs(Widget_t *w) {
|
|
_resize_childs(w);
|
|
}
|
|
|
|
void widget_reset_scale(Widget_t *w) {
|
|
cairo_scale(w->crb, w->scale.cscale_x,w->scale.cscale_y);
|
|
}
|
|
|
|
void widget_set_scale(Widget_t *w) {
|
|
cairo_scale(w->crb, w->scale.rcscale_x,w->scale.rcscale_y);
|
|
}
|
|
|
|
Widget_t *create_window(Xputty *app, Window win,
|
|
int x, int y, int width, int height) {
|
|
|
|
Widget_t *w = (Widget_t*)malloc(sizeof(Widget_t));
|
|
assert(w != NULL);
|
|
debug_print("assert(w)\n");
|
|
XSetWindowAttributes attributes;
|
|
attributes.save_under = True;
|
|
attributes.override_redirect = 0;
|
|
|
|
long event_mask = StructureNotifyMask|ExposureMask|KeyPressMask
|
|
|EnterWindowMask|LeaveWindowMask|ButtonReleaseMask
|
|
|ButtonPressMask|Button1MotionMask|VisibilityChangeMask;
|
|
|
|
|
|
|
|
w->widget = XCreateWindow(app->dpy, win , x, y, width, height, 0,
|
|
CopyFromParent, InputOutput, CopyFromParent,
|
|
CopyFromParent, &attributes);
|
|
debug_print("XCreateWindow\n");
|
|
|
|
XSetLocaleModifiers("");
|
|
w->xim = XOpenIM(app->dpy, 0, 0, 0);
|
|
if(!w->xim){
|
|
XSetLocaleModifiers("@im=none");
|
|
w->xim = XOpenIM(app->dpy, 0, 0, 0);
|
|
}
|
|
|
|
w->xic = XCreateIC(w->xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
|
|
XNClientWindow, w->widget, XNFocusWindow, w->widget, NULL);
|
|
|
|
XSetICFocus(w->xic);
|
|
|
|
XSelectInput(app->dpy, w->widget, event_mask);
|
|
|
|
XSizeHints* win_size_hints;
|
|
win_size_hints = XAllocSizeHints();
|
|
win_size_hints->flags = PMinSize|PBaseSize|PWinGravity;
|
|
win_size_hints->min_width = width/2;
|
|
win_size_hints->min_height = height/2;
|
|
win_size_hints->base_width = width;
|
|
win_size_hints->base_height = height;
|
|
win_size_hints->win_gravity = CenterGravity;
|
|
XSetWMNormalHints(app->dpy, w->widget, win_size_hints);
|
|
XFree(win_size_hints);
|
|
|
|
w->surface = cairo_xlib_surface_create (app->dpy, w->widget,
|
|
DefaultVisual(app->dpy, DefaultScreen(app->dpy)), width, height);
|
|
|
|
assert(cairo_surface_status(w->surface) == CAIRO_STATUS_SUCCESS);
|
|
w->cr = cairo_create(w->surface);
|
|
cairo_select_font_face (w->cr, "Roboto", CAIRO_FONT_SLANT_NORMAL,
|
|
CAIRO_FONT_WEIGHT_NORMAL);
|
|
|
|
w->buffer = cairo_surface_create_similar (w->surface,
|
|
CAIRO_CONTENT_COLOR_ALPHA, width, height);
|
|
assert(cairo_surface_status(w->buffer) == CAIRO_STATUS_SUCCESS);
|
|
w->crb = cairo_create (w->buffer);
|
|
cairo_select_font_face (w->crb, "Roboto", CAIRO_FONT_SLANT_NORMAL,
|
|
CAIRO_FONT_WEIGHT_NORMAL);
|
|
|
|
w->image = NULL;
|
|
|
|
w->flags = IS_WINDOW;
|
|
w->flags &= ~NO_AUTOREPEAT;
|
|
w->flags &= ~FAST_REDRAW;
|
|
w->flags &= ~HIDE_ON_DELETE;
|
|
w->flags &= ~REUSE_IMAGE;
|
|
w->flags &= ~NO_PROPAGATE;
|
|
w->flags &= ~IS_SUBMENU;
|
|
w->flags &= ~DONT_PROPAGATE;
|
|
w->app = app;
|
|
w->parent = &win;
|
|
w->parent_struct = NULL;
|
|
w->private_struct = NULL;
|
|
w->label = NULL;
|
|
memset(w->input_label, 0, 32 * (sizeof w->input_label[0]));
|
|
w->state = 0;
|
|
w->double_click = 0;
|
|
w->data = 0;
|
|
w->x = x;
|
|
w->y = y;
|
|
w->width = width;
|
|
w->height = height;
|
|
w->scale.init_x = x;
|
|
w->scale.init_y = y;
|
|
w->scale.init_width = width;
|
|
w->scale.init_height = height;
|
|
w->scale.scale_x = 0.0;
|
|
w->scale.scale_y = 0.0;
|
|
w->scale.cscale_x = 1.0;
|
|
w->scale.cscale_y = 1.0;
|
|
w->scale.rcscale_x = 1.0;
|
|
w->scale.rcscale_y = 1.0;
|
|
w->scale.ascale = 1.0;
|
|
w->scale.gravity = CENTER;
|
|
w->adj_x = NULL;
|
|
w->adj_y = NULL;
|
|
w->adj = NULL;
|
|
w->color_scheme = (XColor_t*)malloc(sizeof(XColor_t));
|
|
memcpy(w->color_scheme, app->color_scheme, sizeof (struct XColor_t));
|
|
w->childlist = (Childlist_t*)malloc(sizeof(Childlist_t));
|
|
assert(w->childlist != NULL);
|
|
childlist_init(w->childlist);
|
|
w->event_callback = widget_event_loop;
|
|
w->func.expose_callback = _dummy_callback;
|
|
w->func.configure_callback = configure_event;
|
|
w->func.button_press_callback = _dummy1_callback;
|
|
w->func.button_release_callback = _dummy1_callback;
|
|
w->func.double_click_callback = _dummy1_callback;
|
|
w->func.motion_callback = _dummy1_callback;
|
|
w->func.adj_callback = transparent_draw;
|
|
w->func.value_changed_callback = _dummy_callback;
|
|
w->func.key_press_callback = _dummy1_callback;
|
|
w->func.key_release_callback = _dummy1_callback;
|
|
w->func.enter_callback = _dummy_callback;
|
|
w->func.leave_callback = _dummy_callback;
|
|
w->func.user_callback = _dummy_callback;
|
|
w->func.mem_free_callback = _dummy_callback;
|
|
w->func.configure_notify_callback = _dummy_callback;
|
|
w->func.map_notify_callback = _dummy_callback;
|
|
w->func.unmap_notify_callback = _dummy_callback;
|
|
w->func.visibiliy_change_callback = _dummy_callback;
|
|
w->func.dialog_callback = _dummy_callback;
|
|
w->func.dnd_notify_callback = _dummy_callback;
|
|
w->xpaste_callback = _dummy_callback;
|
|
|
|
childlist_add_child(app->childlist,w);
|
|
//XMapWindow(app->dpy, w->widget);
|
|
debug_print("size of Func_t = %lu\n", sizeof(w->func)/sizeof(void*));
|
|
return w;
|
|
}
|
|
|
|
Widget_t *create_widget(Xputty *app, Widget_t *parent,
|
|
int x, int y, int width, int height) {
|
|
|
|
Widget_t *w = (Widget_t*)malloc(sizeof(Widget_t));
|
|
assert(w != NULL);
|
|
debug_print("assert(w)\n");
|
|
XSetWindowAttributes attributes;
|
|
attributes.save_under = True;
|
|
attributes.override_redirect = True;
|
|
|
|
long event_mask = StructureNotifyMask|ExposureMask|KeyPressMask
|
|
|EnterWindowMask|LeaveWindowMask|ButtonReleaseMask
|
|
|ButtonPressMask|Button1MotionMask|VisibilityChangeMask;
|
|
|
|
|
|
|
|
w->widget = XCreateWindow(app->dpy, parent->widget , x, y, width, height, 0,
|
|
CopyFromParent, InputOutput, CopyFromParent,
|
|
CopyFromParent|CWOverrideRedirect, &attributes);
|
|
debug_print("XCreateWindow\n");
|
|
|
|
XSetLocaleModifiers("");
|
|
w->xim = XOpenIM(app->dpy, 0, 0, 0);
|
|
if(!w->xim){
|
|
XSetLocaleModifiers("@im=none");
|
|
w->xim = XOpenIM(app->dpy, 0, 0, 0);
|
|
}
|
|
|
|
w->xic = XCreateIC(w->xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
|
|
XNClientWindow, w->widget, XNFocusWindow, w->widget, NULL);
|
|
|
|
XSetICFocus(w->xic);
|
|
|
|
XSelectInput(app->dpy, w->widget, event_mask);
|
|
|
|
w->surface = cairo_xlib_surface_create (app->dpy, w->widget,
|
|
DefaultVisual(app->dpy, DefaultScreen(app->dpy)), width, height);
|
|
assert(cairo_surface_status(w->surface) == CAIRO_STATUS_SUCCESS);
|
|
w->cr = cairo_create(w->surface);
|
|
cairo_select_font_face (w->cr, "Roboto", CAIRO_FONT_SLANT_NORMAL,
|
|
CAIRO_FONT_WEIGHT_NORMAL);
|
|
|
|
w->buffer = cairo_surface_create_similar (w->surface,
|
|
CAIRO_CONTENT_COLOR_ALPHA, width, height);
|
|
assert(cairo_surface_status(w->buffer) == CAIRO_STATUS_SUCCESS);
|
|
w->crb = cairo_create (w->buffer);
|
|
cairo_select_font_face (w->crb, "Roboto", CAIRO_FONT_SLANT_NORMAL,
|
|
CAIRO_FONT_WEIGHT_NORMAL);
|
|
|
|
w->image = NULL;
|
|
|
|
w->flags = IS_WIDGET | USE_TRANSPARENCY;
|
|
w->flags &= ~NO_AUTOREPEAT;
|
|
w->flags &= ~FAST_REDRAW;
|
|
w->flags &= ~HIDE_ON_DELETE;
|
|
w->flags &= ~REUSE_IMAGE;
|
|
w->flags &= ~NO_PROPAGATE;
|
|
w->flags &= ~IS_SUBMENU;
|
|
w->flags &= ~DONT_PROPAGATE;
|
|
w->app = app;
|
|
w->parent = parent;
|
|
w->parent_struct = NULL;
|
|
w->private_struct = NULL;
|
|
w->label = NULL;
|
|
memset(w->input_label, 0, 32 * (sizeof w->input_label[0]));
|
|
w->state = 0;
|
|
w->double_click = 0;
|
|
w->data = 0;
|
|
w->x = x;
|
|
w->y = y;
|
|
w->width = width;
|
|
w->height = height;
|
|
w->scale.gravity = CENTER;
|
|
w->scale.init_width = width;
|
|
w->scale.init_height = height;
|
|
w->scale.init_x = x;
|
|
w->scale.init_y = y;
|
|
w->scale.scale_x = 0.0;
|
|
w->scale.scale_y = 0.0;
|
|
w->scale.cscale_x = 1.0;
|
|
w->scale.cscale_y = 1.0;
|
|
w->scale.rcscale_x = 1.0;
|
|
w->scale.rcscale_y = 1.0;
|
|
w->scale.ascale = 1.0;
|
|
w->adj_x = NULL;
|
|
w->adj_y = NULL;
|
|
w->adj = NULL;
|
|
w->color_scheme = (XColor_t*)malloc(sizeof(XColor_t));
|
|
memcpy(w->color_scheme, parent->color_scheme, sizeof (struct XColor_t));
|
|
w->childlist = (Childlist_t*)malloc(sizeof(Childlist_t));
|
|
assert(w->childlist != NULL);
|
|
childlist_init(w->childlist);
|
|
childlist_add_child(parent->childlist, w);
|
|
w->event_callback = widget_event_loop;
|
|
w->func.expose_callback = _dummy_callback;
|
|
w->func.configure_callback = configure_event;
|
|
w->func.button_press_callback = _dummy1_callback;
|
|
w->func.button_release_callback = _dummy1_callback;
|
|
w->func.double_click_callback = _dummy1_callback;
|
|
w->func.motion_callback = _dummy1_callback;
|
|
w->func.adj_callback = transparent_draw;
|
|
w->func.value_changed_callback = _dummy_callback;
|
|
w->func.key_press_callback = _dummy1_callback;
|
|
w->func.key_release_callback = _dummy1_callback;
|
|
w->func.enter_callback = _dummy_callback;
|
|
w->func.leave_callback = _dummy_callback;
|
|
w->func.user_callback = _dummy_callback;
|
|
w->func.mem_free_callback = _dummy_callback;
|
|
w->func.configure_notify_callback = _dummy_callback;
|
|
w->func.map_notify_callback = _dummy_callback;
|
|
w->func.unmap_notify_callback = _dummy_callback;
|
|
w->func.visibiliy_change_callback = _dummy_callback;
|
|
w->func.dialog_callback = _dummy_callback;
|
|
w->func.dnd_notify_callback = _dummy_callback;
|
|
w->xpaste_callback = _dummy_callback;
|
|
|
|
childlist_add_child(app->childlist,w);
|
|
//XMapWindow(app->dpy, w->widget);
|
|
debug_print("size of Widget_t = %ld\n", sizeof(struct Widget_t));
|
|
return w;
|
|
}
|
|
|
|
void connect_func(void (**event)(), void (*handler)()) {
|
|
debug_print("address of a is: %p\n", (void*)event);
|
|
debug_print("address of b is: %p\n", (void*)handler);
|
|
*event = handler;
|
|
debug_print("address of a is: %p\n", (void*)(*event));
|
|
}
|
|
|
|
void widget_set_title(Widget_t *w, const char *title) {
|
|
XStoreName(w->app->dpy, w->widget, title);
|
|
XChangeProperty(w->app->dpy, w->widget,
|
|
XInternAtom(w->app->dpy, "_NET_WM_NAME", False),
|
|
XInternAtom(w->app->dpy, "UTF8_STRING", False),
|
|
8, PropModeReplace, (unsigned char *) title,
|
|
strlen(title));
|
|
}
|
|
|
|
void widget_show(Widget_t *w) {
|
|
w->func.map_notify_callback(w, NULL);
|
|
XMapWindow(w->app->dpy, w->widget);
|
|
}
|
|
|
|
void widget_hide(Widget_t *w) {
|
|
int i=0;
|
|
for(;i<w->childlist->elem;i++) {
|
|
widget_hide(w->childlist->childs[i]);
|
|
}
|
|
w->func.unmap_notify_callback(w, NULL);
|
|
XUnmapWindow(w->app->dpy, w->widget);
|
|
}
|
|
|
|
void widget_hide_all(Widget_t *w) {
|
|
int i=0;
|
|
for(;i<w->app->childlist->elem;i++) {
|
|
widget_hide(w->app->childlist->childs[i]);
|
|
}
|
|
w->func.unmap_notify_callback(w, NULL);
|
|
XUnmapWindow(w->app->dpy, w->widget);
|
|
}
|
|
|
|
void widget_show_all(Widget_t *w) {
|
|
if (w->flags & IS_POPUP || w->flags & IS_TOOLTIP ||
|
|
w->flags & IS_SUBMENU) {
|
|
return;
|
|
} else {
|
|
w->func.map_notify_callback(w, NULL);
|
|
XMapWindow(w->app->dpy, w->widget);
|
|
int i=0;
|
|
for(;i<w->childlist->elem;i++) {
|
|
widget_show_all(w->childlist->childs[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void pop_widget_show_all(Widget_t *w) {
|
|
if (w->flags & IS_SUBMENU) return;
|
|
w->func.map_notify_callback(w, NULL);
|
|
XMapWindow(w->app->dpy, w->widget);
|
|
int i=0;
|
|
for(;i<w->childlist->elem;i++) {
|
|
pop_widget_show_all(w->childlist->childs[i]);
|
|
}
|
|
}
|
|
|
|
void submenu_widget_show_all(Widget_t *w) {
|
|
w->func.map_notify_callback(w, NULL);
|
|
XMapWindow(w->app->dpy, w->widget);
|
|
int i=0;
|
|
for(;i<w->childlist->elem;i++) {
|
|
submenu_widget_show_all(w->childlist->childs[i]);
|
|
}
|
|
}
|
|
|
|
void show_tooltip(Widget_t *wid) {
|
|
int i = 0;
|
|
for(;i<wid->childlist->elem;i++) {
|
|
Widget_t *w = wid->childlist->childs[i];
|
|
if (w->flags & IS_TOOLTIP) {
|
|
XWindowAttributes attrs;
|
|
XGetWindowAttributes(w->app->dpy, (Window)w->widget, &attrs);
|
|
int width_t = attrs.width;
|
|
unsigned int mask;
|
|
int x, y, rx, ry;
|
|
Window child, root;
|
|
XQueryPointer(wid->app->dpy, wid->widget, &root, &child, &rx, &ry, &x, &y, &mask);
|
|
int x1, y1;
|
|
XTranslateCoordinates( wid->app->dpy, wid->widget, DefaultRootWindow(wid->app->dpy),
|
|
x, y, &x1, &y1, &child );
|
|
int snum = DefaultScreen(wid->app->dpy);
|
|
int screen_width = DisplayWidth(wid->app->dpy, snum);
|
|
if (x1+10+width_t > screen_width) x1 = x1-width_t-10;
|
|
|
|
XMoveWindow(w->app->dpy,w->widget,x1+10, y1-10);
|
|
widget_show(w);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void hide_tooltip(Widget_t *wid) {
|
|
int i = 0;
|
|
for(;i<wid->childlist->elem;i++) {
|
|
Widget_t *w = wid->childlist->childs[i];
|
|
if (w->flags & IS_TOOLTIP) {
|
|
widget_hide(w);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
Widget_t *get_toplevel_widget(Xputty *main) {
|
|
return main->childlist->childs[0];
|
|
}
|
|
|
|
void expose_widget(Widget_t *w) {
|
|
XEvent exp;
|
|
memset(&exp, 0, sizeof(exp));
|
|
exp.type = Expose;
|
|
exp.xexpose.window = w->widget;
|
|
XSendEvent(w->app->dpy, w->widget, False, ExposureMask, (XEvent *)&exp);
|
|
}
|
|
|
|
void transparent_draw(void * w_, void* user_data) {
|
|
Widget_t *wid = (Widget_t*)w_;
|
|
|
|
cairo_push_group (wid->cr);
|
|
|
|
if (wid->flags & USE_TRANSPARENCY) {
|
|
Widget_t *parent = (Widget_t*)wid->parent;
|
|
XWindowAttributes attrs;
|
|
XGetWindowAttributes(wid->app->dpy, wid->widget, &attrs);
|
|
|
|
debug_print("Widget_t _transparency \n");
|
|
cairo_set_source_surface (wid->crb, parent->buffer, -attrs.x, -attrs.y);
|
|
cairo_paint (wid->crb);
|
|
}
|
|
|
|
cairo_push_group (wid->crb);
|
|
wid->func.expose_callback(wid, user_data);
|
|
cairo_pop_group_to_source (wid->crb);
|
|
cairo_paint (wid->crb);
|
|
|
|
cairo_set_source_surface (wid->cr, wid->buffer,0,0);
|
|
cairo_paint (wid->cr);
|
|
|
|
cairo_pop_group_to_source (wid->cr);
|
|
cairo_paint (wid->cr);
|
|
if ( wid->flags & DONT_PROPAGATE) return;
|
|
_propagate_child_expose(wid);
|
|
}
|
|
|
|
void widget_draw(void * w_, void* user_data) {
|
|
Widget_t *wid = (Widget_t*)w_;
|
|
|
|
cairo_push_group (wid->cr);
|
|
|
|
if (wid->flags & USE_TRANSPARENCY) {
|
|
Widget_t *parent = (Widget_t*)wid->parent;
|
|
XWindowAttributes attrs;
|
|
XGetWindowAttributes(wid->app->dpy, wid->widget, &attrs);
|
|
|
|
debug_print("Widget_t draw widget \n");
|
|
cairo_set_source_surface (wid->crb, parent->buffer, -attrs.x, -attrs.y);
|
|
cairo_paint (wid->crb);
|
|
}
|
|
|
|
cairo_push_group (wid->crb);
|
|
wid->func.expose_callback(wid, user_data);
|
|
cairo_pop_group_to_source (wid->crb);
|
|
cairo_paint (wid->crb);
|
|
|
|
cairo_set_source_surface (wid->cr, wid->buffer,0,0);
|
|
cairo_paint (wid->cr);
|
|
|
|
cairo_pop_group_to_source (wid->cr);
|
|
cairo_paint (wid->cr);
|
|
}
|
|
|
|
void widget_event_loop(void *w_, void* event, Xputty *main, void* user_data) {
|
|
Widget_t *wid = (Widget_t*)w_;
|
|
XEvent *xev = (XEvent*)event;
|
|
|
|
switch(xev->type) {
|
|
case ConfigureNotify:
|
|
wid->func.configure_callback(w_, user_data);
|
|
//transparent_draw(w_, user_data);
|
|
debug_print("Widget_t ConfigureNotify \n");
|
|
break;
|
|
|
|
case VisibilityNotify:
|
|
wid->func.visibiliy_change_callback(w_, user_data);
|
|
debug_print("Widget_t VisibilityNotify \n");
|
|
break;
|
|
|
|
case Expose:
|
|
if (xev->xexpose.count == 0) {
|
|
if ((wid->flags & FAST_REDRAW) == 0) {
|
|
XEvent ev;
|
|
while (XCheckTypedWindowEvent(main->dpy, wid->widget, Expose, &ev)) {}
|
|
}
|
|
transparent_draw(w_, user_data);
|
|
debug_print("Widget_t Expose \n");
|
|
}
|
|
break;
|
|
|
|
case ButtonPress:
|
|
if (wid->state == 4) break;
|
|
if (wid->flags & HAS_TOOLTIP) hide_tooltip(wid);
|
|
_button_press(wid, &xev->xbutton, user_data);
|
|
debug_print("Widget_t ButtonPress %i\n", xev->xbutton.button);
|
|
break;
|
|
|
|
case ButtonRelease:
|
|
{
|
|
XButtonEvent *xbutton = &xev->xbutton;
|
|
_check_grab(wid, xbutton, main);
|
|
_check_submenu(wid, xbutton, main);
|
|
if (wid->state == 4) break;
|
|
if (xbutton->button == Button1) {
|
|
if (xbutton->time < wid->double_click+300) {
|
|
wid->func.double_click_callback(wid, xbutton, user_data);
|
|
break;
|
|
}
|
|
wid->double_click = xbutton->time;
|
|
}
|
|
_has_pointer(wid, &xev->xbutton);
|
|
if(wid->flags & HAS_POINTER) wid->state = 1;
|
|
else wid->state = 0;
|
|
_check_enum(wid, xbutton);
|
|
wid->func.button_release_callback(w_, xbutton, user_data);
|
|
debug_print("Widget_t ButtonRelease %i\n", xev->xbutton.button);
|
|
}
|
|
break;
|
|
|
|
case KeyPress:
|
|
if (wid->state == 4) break;
|
|
_check_keymap(wid, xev->xkey);
|
|
wid->func.key_press_callback(w_, &xev->xkey, user_data);
|
|
debug_print("Widget_t KeyPress %u\n", xev->xkey.keycode);
|
|
break;
|
|
|
|
case KeyRelease:
|
|
{
|
|
if (wid->state == 4) break;
|
|
unsigned short is_retriggered = 0;
|
|
if(wid->flags & NO_AUTOREPEAT) {
|
|
char keys[32];
|
|
XQueryKeymap(main->dpy, keys);
|
|
|
|
if((keys[xev->xkey.keycode>>3] & (0x1 << (xev->xkey.keycode % 8))) &&
|
|
(xev->xkey.keycode > 119 || xev->xkey.keycode < 110)) {
|
|
is_retriggered = 1;
|
|
}
|
|
}
|
|
if (!is_retriggered) {
|
|
wid->func.key_release_callback(w_, &xev->xkey, user_data);
|
|
debug_print("Widget_t KeyRelease %u\n", xev->xkey.keycode);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case LeaveNotify:
|
|
wid->flags &= ~HAS_FOCUS;
|
|
if (wid->state == 4) break;
|
|
if(!(xev->xcrossing.state & Button1Mask) &&
|
|
!(xev->xcrossing.state & Button2Mask) &&
|
|
!(xev->xcrossing.state & Button3Mask)) {
|
|
wid->state = 0;
|
|
wid->func.leave_callback(w_, user_data);
|
|
}
|
|
if (wid->flags & HAS_TOOLTIP) hide_tooltip(wid);
|
|
debug_print("Widget_t LeaveNotify \n");
|
|
break;
|
|
|
|
case EnterNotify:
|
|
wid->flags |= HAS_FOCUS;
|
|
if (wid->state == 4) break;
|
|
if(!(xev->xcrossing.state & Button1Mask) &&
|
|
!(xev->xcrossing.state & Button2Mask) &&
|
|
!(xev->xcrossing.state & Button3Mask)) {
|
|
wid->state = 1;
|
|
wid->func.enter_callback(w_, user_data);
|
|
if (wid->flags & HAS_TOOLTIP) show_tooltip(wid);
|
|
else _hide_all_tooltips(wid);
|
|
}
|
|
debug_print("Widget_t EnterNotify \n");
|
|
break;
|
|
|
|
case MotionNotify:
|
|
if (wid->state == 4) break;
|
|
if (xev->xmotion.state) {
|
|
adj_set_motion_state(wid, xev->xmotion.x, xev->xmotion.y);
|
|
}
|
|
wid->func.motion_callback(w_,&xev->xmotion, user_data);
|
|
debug_print("Widget_t MotionNotify x = %i Y = %i \n",xev->xmotion.x,xev->xmotion.y );
|
|
break;
|
|
|
|
case SelectionRequest:
|
|
if (xev->xselectionrequest.selection != main->selection) break;
|
|
send_to_clipboard(wid, xev);
|
|
break;
|
|
case SelectionClear:
|
|
break;
|
|
case SelectionNotify:
|
|
if (xev->xselection.property == None) {
|
|
wid->xpaste_callback(wid, NULL);
|
|
break;
|
|
}
|
|
if (xev->xselection.selection == main->selection) {
|
|
receive_paste_from_clipboard(wid, xev);
|
|
break;
|
|
}
|
|
debug_print("Widget_t SelectionNotify\n");
|
|
handle_drag_data(wid, xev);
|
|
break;
|
|
|
|
case ClientMessage:
|
|
if (xev->xclient.message_type == main->XdndPosition) {
|
|
debug_print( "XdndPosition\n");
|
|
send_dnd_status_event(wid, xev);
|
|
} else if (xev->xclient.message_type == main->XdndEnter) {
|
|
debug_print( "XdndEnter\n");
|
|
handle_dnd_enter(main, xev);
|
|
} else if (xev->xclient.message_type == main->XdndLeave) {
|
|
debug_print( "XdndLeave\n");
|
|
main->dnd_type = None;
|
|
main->dnd_source_window = 0;
|
|
main->dnd_version = 0;
|
|
} else if (xev->xclient.message_type == main->XdndDrop) {
|
|
if ((DND_SOURCE_WIN(xev) != main->dnd_source_window) ||
|
|
main->dnd_type == None || main->dnd_source_window == 0) {
|
|
break;
|
|
}
|
|
XConvertSelection(main->dpy, main->XdndSelection,
|
|
main->dnd_type, main->XdndSelection, wid->widget, CurrentTime);
|
|
|
|
send_dnd_finished_event(wid, xev);
|
|
} else if (xev->xclient.message_type == XInternAtom(wid->app->dpy, "WIDGET_DESTROY", 1)) {
|
|
int ch = childlist_has_child(wid->childlist);
|
|
if (ch) {
|
|
int i = ch;
|
|
for(;i>0;i--) {
|
|
quit_widget(wid->childlist->childs[i-1]);
|
|
}
|
|
quit_widget(wid);
|
|
} else {
|
|
destroy_widget(wid,main);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void widget_set_dnd_aware(Widget_t *w) {
|
|
Atom dnd_version = 5;
|
|
XChangeProperty (w->app->dpy, w->widget, w->app->XdndAware, XA_ATOM,
|
|
32, PropModeReplace, (unsigned char*)&dnd_version, 1);
|
|
}
|
|
|
|
void widget_set_dnd_unaware(Widget_t *w) {
|
|
XDeleteProperty(w->app->dpy, w->widget, w->app->XdndAware);
|
|
}
|
|
|
|
void strremove(char *str, const char *sub) {
|
|
char *p, *q, *r;
|
|
if ((q = r = strstr(str, sub)) != NULL) {
|
|
size_t len = strlen(sub);
|
|
while ((r = strstr(p = r + len, sub)) != NULL) {
|
|
while (p < r)
|
|
*q++ = *p++;
|
|
}
|
|
while ((*q++ = *p++) != '\0')
|
|
continue;
|
|
}
|
|
}
|
|
|
|
void strdecode(char *target, const char *needle, const char *replacement) {
|
|
char buffer[1024] = { 0 };
|
|
char *insert_point = &buffer[0];
|
|
const char *tmp = target;
|
|
size_t needle_len = strlen(needle);
|
|
size_t repl_len = strlen(replacement);
|
|
|
|
while (1) {
|
|
const char *p = strstr(tmp, needle);
|
|
if (p == NULL) {
|
|
strcpy(insert_point, tmp);
|
|
break;
|
|
}
|
|
memcpy(insert_point, tmp, p - tmp);
|
|
insert_point += p - tmp;
|
|
memcpy(insert_point, replacement, repl_len);
|
|
insert_point += repl_len;
|
|
tmp = p + needle_len;
|
|
}
|
|
strcpy(target, buffer);
|
|
}
|
|
|
|
|
|
void handle_drag_data(Widget_t *w, XEvent* event) {
|
|
if (event->xselection.property != w->app->XdndSelection) return;
|
|
|
|
Atom type;
|
|
int format;
|
|
unsigned long count = 0, remaining;
|
|
unsigned char* data = 0;
|
|
|
|
XGetWindowProperty(w->app->dpy,w->widget, event->xselection.property,
|
|
0, 65536, True, w->app->dnd_type, &type, &format,
|
|
&count, &remaining, &data);
|
|
|
|
send_dnd_finished_event (w, event);
|
|
|
|
if (!data || count == 0) {
|
|
return;
|
|
}
|
|
char* dndfile = (char*)data;
|
|
strdecode(dndfile, "%20", " ");
|
|
strremove(dndfile, "file://");
|
|
w->func.dnd_notify_callback(w, (void*)&dndfile);
|
|
w->app->dnd_type = None;
|
|
w->app->dnd_source_window = 0;
|
|
free(data);
|
|
}
|
|
|
|
void handle_dnd_enter(Xputty *main, XEvent* event) {
|
|
main->dnd_source_window = DND_SOURCE_WIN(event);
|
|
main->dnd_version = 0;
|
|
if (DND_STATUS_ACCEPT(event)) {
|
|
main->dnd_version = DND_VERSION(event);
|
|
if (main->dnd_version > 5) return;
|
|
Atom type = 0;
|
|
int format;
|
|
unsigned long count, remaining;
|
|
unsigned char *data = 0;
|
|
|
|
XGetWindowProperty (main->dpy, main->dnd_source_window, main->XdndTypeList,
|
|
0, 0x8000000L, False, XA_ATOM, &type, &format, &count, &remaining, &data);
|
|
if (!data || type != XA_ATOM || format != 32) {
|
|
if (data) {
|
|
XFree (data);
|
|
}
|
|
return;
|
|
}
|
|
Atom* types = (Atom*)data;
|
|
for (unsigned long l = 1; l < count; l++) {
|
|
if ((types[l] == main->dnd_type_uri) ||
|
|
(types[l] == main->dnd_type_text) ||
|
|
(types[l] == main->dnd_type_utf8)) {
|
|
main->dnd_type = types[l];
|
|
break;
|
|
}
|
|
}
|
|
if (data) {
|
|
XFree (data);
|
|
}
|
|
} else {
|
|
for (int i = 2; i < 5; ++i) {
|
|
if ((event->xclient.data.l[i] == main->dnd_type_uri) ||
|
|
(event->xclient.data.l[i] == main->dnd_type_text) ||
|
|
(event->xclient.data.l[i] == main->dnd_type_utf8)) {
|
|
main->dnd_type = event->xclient.data.l[i];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void send_dnd_status_event(Widget_t *w, XEvent* event) {
|
|
XEvent xev;
|
|
memset (&xev, 0, sizeof (XEvent));
|
|
xev.xany.type = ClientMessage;
|
|
xev.xany.display = w->app->dpy;
|
|
xev.xclient.window = w->app->dnd_source_window;
|
|
xev.xclient.message_type = w->app->XdndStatus;
|
|
xev.xclient.format = 32;
|
|
xev.xclient.data.l[0] = event->xany.window;
|
|
xev.xclient.data.l[1] = (w->app->dnd_type != None) ? 1 : 0;
|
|
xev.xclient.data.l[2] = DND_DROP_TIME(event);
|
|
xev.xclient.data.l[3] = 0;
|
|
xev.xclient.data.l[4] = w->app->XdndActionCopy;
|
|
XSendEvent (w->app->dpy, w->app->dnd_source_window, False, NoEventMask, &xev);
|
|
}
|
|
|
|
void send_dnd_finished_event(Widget_t *w, XEvent* event) {
|
|
if (w->app->dnd_version < 2) {
|
|
return;
|
|
}
|
|
XEvent xev;
|
|
memset (&xev, 0, sizeof (XEvent));
|
|
xev.xany.type = ClientMessage;
|
|
xev.xany.display = w->app->dpy;
|
|
xev.xclient.window = w->app->dnd_source_window;
|
|
xev.xclient.message_type = w->app->XdndFinished;
|
|
xev.xclient.format = 32;
|
|
xev.xclient.data.l[0] = event->xany.window;
|
|
xev.xclient.data.l[1] = 1;
|
|
xev.xclient.data.l[2] = w->app->XdndActionCopy;
|
|
XSendEvent (w->app->dpy, w->app->dnd_source_window, False, NoEventMask, &xev);
|
|
}
|
|
|
|
int have_paste(Widget_t *w) {
|
|
return XGetSelectionOwner(w->app->dpy,w->app->selection);
|
|
}
|
|
|
|
void request_paste_from_clipboard(Widget_t *w) {
|
|
Atom XSEL_DATA = XInternAtom(w->app->dpy, "XSEL_DATA", 0);
|
|
XConvertSelection(w->app->dpy, w->app->selection, w->app->UTF8, XSEL_DATA, w->widget, CurrentTime);
|
|
}
|
|
|
|
void receive_paste_from_clipboard(Widget_t *w, XEvent* event) {
|
|
if(event->xselection.property) {
|
|
Atom target;
|
|
char * data = NULL;
|
|
int format;
|
|
unsigned long N, size;
|
|
XGetWindowProperty(event->xselection.display, event->xselection.requestor,
|
|
event->xselection.property, 0L,(~0L), 0, AnyPropertyType, &target,
|
|
&format, &size, &N,(unsigned char**)&data);
|
|
if(target == w->app->UTF8 || target == XA_STRING) {
|
|
free(w->app->ctext);
|
|
w->app->ctext = NULL;
|
|
w->app->ctext = (unsigned char*)strndup(data, size);
|
|
XFree(data);
|
|
}
|
|
XDeleteProperty(event->xselection.display, event->xselection.requestor, event->xselection.property);
|
|
w->xpaste_callback(w, (void*)&w->app->ctext);
|
|
}
|
|
}
|
|
|
|
void copy_to_clipboard(Widget_t *w, char* text, int size) {
|
|
XSetSelectionOwner (w->app->dpy, w->app->selection, w->widget, 0);
|
|
if (XGetSelectionOwner (w->app->dpy, w->app->selection) != w->widget) return;
|
|
free(w->app->ctext);
|
|
w->app->ctext = NULL;
|
|
w->app->ctext = (unsigned char*)strndup(text, size);
|
|
w->app->csize = size;
|
|
}
|
|
|
|
void send_to_clipboard(Widget_t *w, XEvent* event) {
|
|
XSelectionRequestEvent * xsr = &event->xselectionrequest;
|
|
XSelectionEvent xev;
|
|
memset (&xev, 0, sizeof (XSelectionEvent));
|
|
int R = 0;
|
|
xev.type = SelectionNotify;
|
|
xev.display = xsr->display;
|
|
xev.requestor = xsr->requestor;
|
|
xev.selection = xsr->selection;
|
|
xev.time = xsr->time;
|
|
xev.target = xsr->target;
|
|
xev.property = xsr->property;
|
|
if (xev.target == w->app->targets_atom) {
|
|
R = XChangeProperty (xev.display, xev.requestor, xev.property, XA_ATOM, 32,
|
|
PropModeReplace, (unsigned char*)&w->app->UTF8, 1);
|
|
} else if (xev.target == XA_STRING || xev.target == w->app->text_atom) {
|
|
R = XChangeProperty(xev.display, xev.requestor, xev.property, XA_STRING, 8,
|
|
PropModeReplace, w->app->ctext, w->app->csize);
|
|
} else if (xev.target == w->app->UTF8) {
|
|
R = XChangeProperty(xev.display, xev.requestor, xev.property, w->app->UTF8, 8,
|
|
PropModeReplace, w->app->ctext, w->app->csize);
|
|
} else {
|
|
xev.property = None;
|
|
}
|
|
if ((R & 2) == 0) XSendEvent (w->app->dpy, xev.requestor, 0, 0, (XEvent *)&xev);
|
|
debug_print("send to clipboard %s\n", w->app->ctext);
|
|
}
|
|
|
|
void send_configure_event(Widget_t *w,int x, int y, int width, int height) {
|
|
XConfigureEvent notify;
|
|
memset(¬ify, 0, sizeof(notify));
|
|
notify.type = ConfigureNotify;
|
|
notify.display = w->app->dpy;
|
|
notify.send_event = True;
|
|
notify.event = w->widget;
|
|
notify.window = w->widget;
|
|
notify.x = x;
|
|
notify.y = y;
|
|
notify.width = width;
|
|
notify.height = height;
|
|
notify.border_width = 0;
|
|
notify.above = None;
|
|
notify.override_redirect = 1;
|
|
XSendEvent( w->app->dpy, w->widget, true, StructureNotifyMask, (XEvent*)¬ify );
|
|
}
|
|
|
|
void send_button_press_event(Widget_t *w) {
|
|
XEvent event;
|
|
memset(&event, 0, sizeof(XEvent));
|
|
XWindowAttributes attr;
|
|
XGetWindowAttributes(w->app->dpy, w->widget, &attr);
|
|
event.type = ButtonPress;
|
|
event.xbutton.same_screen = true;
|
|
event.xbutton.root = None;
|
|
event.xbutton.window = w->widget;
|
|
event.xbutton.subwindow = None;
|
|
event.xbutton.x = 1;
|
|
event.xbutton.y = 1;
|
|
event.xbutton.x_root = attr.x;
|
|
event.xbutton.y_root = attr.y;
|
|
event.xbutton.state = 0;
|
|
event.xbutton.button = Button1;
|
|
XSendEvent(w->app->dpy, PointerWindow, True, ButtonPressMask, &event);
|
|
}
|
|
|
|
void send_button_release_event(Widget_t *w) {
|
|
XEvent event;
|
|
memset(&event, 0, sizeof(XEvent));
|
|
XWindowAttributes attr;
|
|
XGetWindowAttributes(w->app->dpy, w->widget, &attr);
|
|
event.type = ButtonRelease;
|
|
event.xbutton.same_screen = true;
|
|
event.xbutton.root = None;
|
|
event.xbutton.window = w->widget;
|
|
event.xbutton.subwindow = None;
|
|
event.xbutton.x = 1;
|
|
event.xbutton.y = 1;
|
|
event.xbutton.x_root = attr.x;
|
|
event.xbutton.y_root = attr.y;
|
|
event.xbutton.state = 0;
|
|
event.xbutton.button = Button1;
|
|
XSendEvent(w->app->dpy, PointerWindow, True, ButtonReleaseMask, &event);
|
|
}
|
|
|
|
void send_systray_message(Widget_t *w) {
|
|
XEvent event;
|
|
Screen *xscreen;
|
|
char buf[256];
|
|
buf[0]=0;
|
|
|
|
xscreen=DefaultScreenOfDisplay(w->app->dpy);
|
|
sprintf(buf,"_NET_SYSTEM_TRAY_S%d",XScreenNumberOfScreen (xscreen));
|
|
Atom selection_atom = XInternAtom (w->app->dpy,buf,0);
|
|
|
|
Window tray = XGetSelectionOwner (w->app->dpy,selection_atom);
|
|
Atom visualatom = XInternAtom(w->app->dpy, "_NET_SYSTEM_TRAY_VISUAL", False);
|
|
VisualID value = XVisualIDFromVisual(DefaultVisual(w->app->dpy, DefaultScreen(w->app->dpy)));
|
|
XChangeProperty(w->app->dpy, w->widget, visualatom, XA_VISUALID, 32,
|
|
PropModeReplace, (unsigned char*)&value, 1);
|
|
|
|
if ( tray != None) {
|
|
XSelectInput (w->app->dpy,tray,StructureNotifyMask);
|
|
/* get tray color and set as background */
|
|
XColor c;
|
|
XWindowAttributes attrs;
|
|
XGetWindowAttributes(w->app->dpy, DefaultRootWindow(w->app->dpy), &attrs);
|
|
|
|
XImage *image = NULL;
|
|
default_error_handler = XSetErrorHandler(intern_error_handler);
|
|
image = XGetImage(w->app->dpy, DefaultRootWindow(w->app->dpy),
|
|
attrs.width -2, attrs.height -2, 1, 1, AllPlanes, XYPixmap);
|
|
XSetErrorHandler(default_error_handler);
|
|
if (image) {
|
|
c.pixel = XGetPixel(image, 0, 0);
|
|
XQueryColor (w->app->dpy, DefaultColormap(w->app->dpy, DefaultScreen (w->app->dpy)), &c);
|
|
double r = (double)c.red/65535.0;
|
|
double g = (double)c.green/65535.0;
|
|
double b = (double)c.blue/65535.0;
|
|
set_systray_color(w->app, r, g, b, 1.0);
|
|
XDestroyImage(image);
|
|
}
|
|
}
|
|
|
|
memset(&event, 0, sizeof(event));
|
|
event.xclient.type = ClientMessage;
|
|
event.xclient.window = tray;
|
|
event.xclient.message_type = XInternAtom (w->app->dpy, "_NET_SYSTEM_TRAY_OPCODE", False );
|
|
event.xclient.format = 32;
|
|
event.xclient.data.l[0] = CurrentTime;
|
|
event.xclient.data.l[1] = SYSTEM_TRAY_REQUEST_DOCK;
|
|
event.xclient.data.l[2] = w->widget;
|
|
event.xclient.data.l[3] = 0;
|
|
event.xclient.data.l[4] = 0;
|
|
|
|
XSendEvent(w->app->dpy, tray, False, NoEventMask, &event);
|
|
}
|
|
|
|
void quit(Widget_t *w) {
|
|
Atom WM_DELETE_WINDOW = XInternAtom(w->app->dpy, "WM_DELETE_WINDOW", True);
|
|
XClientMessageEvent xevent;
|
|
xevent.type = ClientMessage;
|
|
xevent.message_type = WM_DELETE_WINDOW;
|
|
xevent.display = w->app->dpy;
|
|
xevent.window = get_toplevel_widget(w->app)->widget;
|
|
xevent.format = 16;
|
|
xevent.data.l[0] = WM_DELETE_WINDOW;
|
|
XSendEvent(w->app->dpy, w->widget, 0, 0, (XEvent *)&xevent);
|
|
}
|
|
|
|
void quit_widget(Widget_t *w) {
|
|
Atom QUIT_WIDGET = XInternAtom(w->app->dpy, "WIDGET_DESTROY", False);
|
|
XClientMessageEvent xevent;
|
|
xevent.type = ClientMessage;
|
|
xevent.message_type = QUIT_WIDGET;
|
|
xevent.display = w->app->dpy;
|
|
xevent.window = w->widget;
|
|
xevent.format = 16;
|
|
xevent.data.l[0] = 1;
|
|
XSendEvent(w->app->dpy, w->widget, 0, 0, (XEvent *)&xevent);
|
|
}
|
|
|