1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303
|
/* -------------------------------
* vim:tabstop=4:shiftwidth=4
* embed.c
* Fri, 03 Sep 2004 20:38:55 +0700
* -------------------------------
* embedding cycle implementation
* -------------------------------*/
#include "config.h"
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <unistd.h>
#include <assert.h>
#ifdef DELAY_EMBEDDING_CONFIRMATION
#include <pthread.h>
#endif
#include "embed.h"
#include "common.h"
#include "tray.h"
#include "debug.h"
#include "icons.h"
#include "kde_tray.h"
#include "settings.h"
#include "xembed.h"
#include "xutils.h"
#define CALC_INNER_POS(x_, y_, ti_) do { \
x_ = (ti_->l.icn_rect.w - ti_->l.wnd_sz.x) / 2; \
y_ = (ti_->l.icn_rect.h - ti_->l.wnd_sz.y) / 2; \
} while (0);
#ifdef DELAY_EMBEDDING_CONFIRMATION
void *send_delayed_confirmation(void *dummy)
{
struct TrayIcon* ti = (struct TrayIcon *) dummy;
Display *dpy;
if ((dpy = XOpenDisplay(settings.display_str)) != NULL) {
LOG_TRACE(("will now sleep for %d seconds\n", settings.confirmation_delay));
sleep(settings.confirmation_delay);
LOG_TRACE(("sending embedding confirmation\n"));
x11_send_client_msg32(dpy,
tray_data.tray,
tray_data.tray,
tray_data.xa_tray_opcode,
0,
STALONE_TRAY_DOCK_CONFIRMED,
ti->wid, 0, 0);
XSync(dpy, False);
XClose(dpy);
} else {
DIE_IE(("failed to initialize display\n"));
}
pthread_exit(NULL);
}
#endif
int embedder_embed(struct TrayIcon *ti)
{
int x, y, rc;
XSetWindowAttributes xswa;
/* If the icon is being embedded as hidden,
* we just start listening for property changes
* to track _XEMBED mapped state */
if (!ti->is_visible) {
XSelectInput(tray_data.dpy, ti->wid, PropertyChangeMask);
return x11_ok();
}
/* 0. Start listening for events on icon window */
XSelectInput(tray_data.dpy, ti->wid, StructureNotifyMask | PropertyChangeMask);
if (!x11_ok()) RETURN_STATUS(FAILURE);
/* 1. Calculate position of mid-parent window */
CALC_INNER_POS(x, y, ti);
LOG_TRACE(("position of icon 0x%x inside the tray: (%d, %d)\n", ti->wid, x, y));
/* 2. Create mid-parent window */
ti->mid_parent = XCreateSimpleWindow(tray_data.dpy, tray_data.tray,
ti->l.icn_rect.x + x, ti->l.icn_rect.y + y,
ti->l.wnd_sz.x, ti->l.wnd_sz.y, 0, 0, 0);
/* 2.5. Setup mid-parent window properties */
xswa.win_gravity = settings.bit_gravity;
XChangeWindowAttributes(tray_data.dpy, ti->mid_parent, CWWinGravity, &xswa);
#ifndef DEBUG_HIGHLIGHT_MIDPARENT
XSetWindowBackgroundPixmap(tray_data.dpy, ti->mid_parent, ParentRelative);
#else
XSetWindowBackgroundPixmap(tray_data.dpy, ti->mid_parent, 0);
#endif
if (!x11_ok() || ti->mid_parent == None) RETURN_STATUS(FAILURE);
LOG_TRACE(("created mid-parent window 0x%x\n", ti->mid_parent));
/* 3. Embed window into mid-parent */
switch (ti->cmode) {
case CM_KDE:
case CM_FDO:
XReparentWindow(tray_data.dpy, ti->wid, ti->mid_parent, 0, 0);
XMapRaised(tray_data.dpy, ti->wid);
break;
default:
break;
}
/* 4. Show mid-parent */
XMapWindow(tray_data.dpy, ti->mid_parent);
/* mid-parent must be lowered so that it does not osbcure
* scollbar windows */
XLowerWindow(tray_data.dpy, ti->mid_parent);
if (!x11_ok()) RETURN_STATUS(FAILURE);
#ifndef DELAY_EMBEDDING_CONFIRMATION
/* 5. Send message confirming embedding */
rc = x11_send_client_msg32(tray_data.dpy,
tray_data.tray,
tray_data.tray,
tray_data.xa_tray_opcode,
0,
STALONE_TRAY_DOCK_CONFIRMED,
ti->wid, 0, 0);
RETURN_STATUS(rc != 0);
#else
/* This is here for debugging purposes */
{
pthread_t delayed_thread;
pthread_create(&delayed_thread, NULL, send_delayed_confirmation, (void *) ti);
LOG_TRACE(("sent delayed confirmation\n"));
RETURN_STATUS(SUCCESS);
}
#endif
}
int embedder_unembed(struct TrayIcon *ti)
{
if (!ti->is_embedded) return SUCCESS;
switch (ti->cmode) {
case CM_KDE:
case CM_FDO:
/* Unembed icon as described in system tray protocol */
if (ti->is_embedded) {
XSelectInput(tray_data.dpy, ti->wid, NoEventMask);
XUnmapWindow(tray_data.dpy, ti->wid);
XReparentWindow(tray_data.dpy, ti->wid, DefaultRootWindow(tray_data.dpy),
ti->l.icn_rect.x, ti->l.icn_rect.y);
XMapRaised(tray_data.dpy, ti->wid);
if (!x11_ok()) LOG_ERROR(("failed to move icon 0x%x out of the tray\n"));
}
/* Destroy mid-parent */
if (ti->mid_parent != None) {
XDestroyWindow(tray_data.dpy, ti->mid_parent);
if (!x11_ok()) LOG_ERROR(("failed to destroy icon mid-parent 0x%x\n", ti->mid_parent));
}
break;
default:
LOG_ERR_IE(("Error: the compatibility mode %d is not supported (should not happen)\n", ti->cmode));
return FAILURE;
}
LOG_TRACE(("done unembedding 0x%x\n", ti->wid));
RETURN_STATUS(x11_ok() == 0); /* This resets error status for the generations to come (XXX) */
}
int embedder_hide(struct TrayIcon *ti)
{
XUnmapWindow(tray_data.dpy, ti->mid_parent);
/* We do not wany any StructureNotify events for icon window anymore */
XSelectInput(tray_data.dpy, ti->wid, PropertyChangeMask);
if (!x11_ok()) {
ti->is_invalid = True;
return FAILURE;
} else {
ti->is_size_set = False;
ti->num_size_resets = 0;
ti->is_visible = False;
return SUCCESS;
}
}
int embedder_show(struct TrayIcon *ti)
{
unsigned int x, y;
/* If the window has never been embedded,
* perform real embedding */
if (ti->mid_parent == None) {
ti->is_visible = True;
return embedder_embed(ti);
}
/* 0. calculate new position for mid-parent */
CALC_INNER_POS(x, y, ti);
/* 1. move mid-parent to new location */
XMoveResizeWindow(tray_data.dpy, ti->mid_parent,
ti->l.icn_rect.x + x, ti->l.icn_rect.y + y,
ti->l.wnd_sz.x, ti->l.wnd_sz.y);
/* 2. adjust icon position inside mid-parent */
XMoveWindow(tray_data.dpy, ti->wid, 0, 0);
/* 3. map icon ? */
XMapRaised(tray_data.dpy, ti->wid);
/* 4. map mid-parent */
XMapWindow(tray_data.dpy, ti->mid_parent);
XSelectInput(tray_data.dpy, ti->wid, StructureNotifyMask | PropertyChangeMask);
if (!x11_ok()) {
ti->is_invalid = True;
return FAILURE;
} else {
ti->is_visible = True;
return SUCCESS;
}
}
static int update_forced = False;
static int embedder_update_window_position(struct TrayIcon *ti)
{
int x, y;
/* Ignore hidden icons */
if (!ti->is_visible)
return NO_MATCH;
/* Update only those icons that do want it (everyone if update was forced) */
if (!update_forced && !ti->is_updated && !ti->is_resized && ti->is_embedded)
return NO_MATCH;
LOG_TRACE(("Updating position of icon 0x%x\n", ti->wid));
/* Recalculate icon position */
CALC_INNER_POS(x, y, ti);
/* Reset the flags */
ti->is_resized = False;
ti->is_updated = False;
/* Move mid-parent window */
XMoveResizeWindow(tray_data.dpy, ti->mid_parent,
ti->l.icn_rect.x + x, ti->l.icn_rect.y + y,
ti->l.wnd_sz.x, ti->l.wnd_sz.y);
/* Sanitize icon position inside mid-parent */
XMoveWindow(tray_data.dpy, ti->wid, 0, 0);
/* Refresh the icon */
embedder_refresh(ti);
if (!x11_ok()) {
LOG_TRACE(("failed to update position of icon 0x%x\n", ti->wid));
ti->is_invalid = True;
}
return NO_MATCH;
}
int embedder_update_positions(int forced)
{
/* I wish C had closures =( */
update_forced = forced;
icon_list_forall(&embedder_update_window_position);
return SUCCESS;
}
int embedder_refresh(struct TrayIcon *ti)
{
if (!ti->is_visible) return NO_MATCH;
XClearWindow(tray_data.dpy, ti->mid_parent);
x11_refresh_window(tray_data.dpy, ti->wid, ti->l.wnd_sz.x, ti->l.wnd_sz.y, True);
/* Check if the icon has survived all these manipulations */
if (!x11_ok()) {
LOG_TRACE(("could not refresh 0x%x\n", ti->wid));
ti->is_invalid = True;
}
return NO_MATCH;
}
/* This function defines initial icon size or
* is used to reset size of the icon window */
int embedder_reset_size(struct TrayIcon *ti)
{
struct Point icon_sz;
int rc = FAILURE;
/* Do not reset size for non-KDE icons with size set if icon_resizes
* are handled */
if (ti->is_size_set && ti->cmode != CM_KDE && !settings.kludge_flags & KLUDGE_FORCE_ICONS_SIZE)
return SUCCESS;
/* Increase counter of size resets for given icon. If this number
* exeeds the threshold, do nothing. This should work around the icons
* that react badly to size changes */
if (ti->is_size_set) ti->num_size_resets++;
if (ti->num_size_resets > ICON_SIZE_RESETS_THRESHOLD) return SUCCESS;
if (ti->cmode == CM_KDE) {
icon_sz.x = settings.icon_size < KDE_ICON_SIZE ? settings.icon_size : KDE_ICON_SIZE;
icon_sz.y = icon_sz.x;
} else {
/* If icon hints are to be respected, retrive the data */
if (settings.kludge_flags & KLUDGE_USE_ICONS_HINTS)
rc = x11_get_window_min_size(tray_data.dpy, ti->wid, &icon_sz.x, &icon_sz.y);
/* If this has failed, or icon hinst are not respected, or minimal size hints
* are too small, fall back to default values */
if (!rc ||
!settings.kludge_flags & KLUDGE_USE_ICONS_HINTS ||
settings.kludge_flags & KLUDGE_FORCE_ICONS_SIZE ||
(icon_sz.x < settings.icon_size && icon_sz.y < settings.icon_size))
{
icon_sz.x = settings.icon_size;
icon_sz.y = settings.icon_size;
}
}
LOG_TRACE(("proposed icon size: %dx%d\n", icon_sz.x, icon_sz.y));
if (x11_set_window_size(tray_data.dpy, ti->wid, icon_sz.x, icon_sz.y)) {
ti->l.wnd_sz = icon_sz;
ti->is_size_set = True;
return SUCCESS;
} else {
ti->is_invalid = True;
return FAILURE;
}
}
|