695 lines
18 KiB
C
695 lines
18 KiB
C
/* WMix 3.0 -- a mixer using the OSS mixer API.
|
|
* Copyright (C) 2000, 2001
|
|
* Daniel Richard G. <skunk@mit.edu>,
|
|
* timecop <timecop@japan.co.jp>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <math.h>
|
|
|
|
#include <X11/X.h>
|
|
#include <X11/Xlib.h>
|
|
#include <X11/Xutil.h>
|
|
#include <X11/Xatom.h>
|
|
#include <X11/extensions/shape.h>
|
|
#include <X11/xpm.h>
|
|
#include <X11/cursorfont.h>
|
|
#include <X11/extensions/Xrandr.h>
|
|
|
|
#include "include/master.xpm"
|
|
#include "include/led-on.xpm"
|
|
#include "include/led-off.xpm"
|
|
|
|
#include "include/common.h"
|
|
#include "include/misc.h"
|
|
#include "include/mixer.h"
|
|
#include "include/ui_x.h"
|
|
#include "include/config.h"
|
|
|
|
|
|
#ifndef PI
|
|
#define PI M_PI
|
|
#endif
|
|
|
|
#define LED_POS_RADIUS 8
|
|
#define KNOB_CENTER_X 49
|
|
#define KNOB_CENTER_Y 48
|
|
#define LED_WIDTH 6
|
|
#define LED_HEIGHT 6
|
|
|
|
typedef struct _Dockapp Dockapp;
|
|
|
|
struct _Dockapp {
|
|
int width;
|
|
int height;
|
|
Pixmap pixmap;
|
|
Pixmap mask;
|
|
GC gc;
|
|
int ctlength;
|
|
|
|
Window osd;
|
|
GC osd_gc;
|
|
int osd_width;
|
|
int osd_x;
|
|
int osd_y;
|
|
bool osd_mapped;
|
|
|
|
};
|
|
|
|
static Pixmap led_on_pixmap;
|
|
static Pixmap led_on_mask;
|
|
static Pixmap led_off_pixmap;
|
|
static Pixmap led_off_mask;
|
|
|
|
#define copy_xpm_area(x, y, w, h, dx, dy) \
|
|
XCopyArea(display, dockapp.pixmap, dockapp.pixmap, dockapp.gc, \
|
|
x, y, w, h, dx, dy)
|
|
|
|
/* local prototypes */
|
|
static Cursor create_null_cursor(Display *x_display);
|
|
|
|
/* ui stuff */
|
|
static void draw_stereo_led(void);
|
|
static void draw_rec_led(void);
|
|
static void draw_mute_led(void);
|
|
static void draw_percent(void);
|
|
static void draw_knob(float volume);
|
|
static void draw_slider(float offset);
|
|
|
|
/* global variables */
|
|
static Dockapp dockapp;
|
|
static Display *display;
|
|
static Window win;
|
|
static Window iconwin;
|
|
static Cursor hand_cursor;
|
|
static Cursor null_cursor;
|
|
static Cursor norm_cursor;
|
|
static Cursor bar_cursor;
|
|
static Bool have_randr;
|
|
|
|
/* public methods */
|
|
void dockapp_init(Display *x_display, Bool randr)
|
|
{
|
|
display = x_display;
|
|
have_randr = randr;
|
|
dockapp.osd = 0;
|
|
dockapp.gc = 0;
|
|
}
|
|
|
|
void redraw_window(void)
|
|
{
|
|
XCopyArea(display, dockapp.pixmap, iconwin, dockapp.gc,
|
|
0, 0, dockapp.width, dockapp.height, 0, 0);
|
|
XCopyArea(display, dockapp.pixmap, win, dockapp.gc,
|
|
0, 0, dockapp.width, dockapp.height, 0, 0);
|
|
}
|
|
|
|
void ui_update(void)
|
|
{
|
|
draw_stereo_led();
|
|
draw_rec_led();
|
|
draw_mute_led();
|
|
draw_knob(mixer_get_volume());
|
|
draw_slider(mixer_get_balance());
|
|
redraw_window();
|
|
}
|
|
|
|
void knob_turn(float delta)
|
|
{
|
|
mixer_set_volume_rel(delta);
|
|
draw_knob(mixer_get_volume());
|
|
redraw_window();
|
|
}
|
|
|
|
void slider_move(float delta)
|
|
{
|
|
mixer_set_balance_rel(delta);
|
|
draw_slider(mixer_get_balance());
|
|
redraw_window();
|
|
}
|
|
|
|
int blit_string(const char *text)
|
|
{
|
|
register int i;
|
|
register int c;
|
|
register int k;
|
|
|
|
k = 0;
|
|
copy_xpm_area(0, 87, 256, 9, 0, 96);
|
|
|
|
for (i = 0; text[i] || i > 31; i++) {
|
|
c = toupper(text[i]);
|
|
if (c == '-') {
|
|
copy_xpm_area(60, 67, 6, 8, k, 96);
|
|
k += 6;
|
|
}
|
|
if (c == ' ') {
|
|
copy_xpm_area(66, 67, 6, 8, k, 96);
|
|
k += 6;
|
|
}
|
|
if (c == '.') {
|
|
copy_xpm_area(72, 67, 6, 8, k, 96);
|
|
k += 6;
|
|
}
|
|
if (c >= 'A' && c <= 'Z') { /* letter */
|
|
c = c - 'A';
|
|
copy_xpm_area(c * 6, 77, 6, 8, k, 96);
|
|
k += 6;
|
|
} else if (c >= '0' && c <= '9') { /* number */
|
|
c = c - '0';
|
|
copy_xpm_area(c * 6, 67, 6, 8, k, 96);
|
|
k += 6;
|
|
}
|
|
}
|
|
dockapp.ctlength = k;
|
|
return k;
|
|
}
|
|
|
|
void scroll_text(int x, int y, int width, bool reset)
|
|
{
|
|
static int pos;
|
|
static int first;
|
|
static int stop;
|
|
|
|
/* no text scrolling at all */
|
|
if (!config.scrolltext) {
|
|
if (!reset)
|
|
return;
|
|
copy_xpm_area(0, 96, 58, 9, x, y);
|
|
redraw_window();
|
|
return;
|
|
}
|
|
|
|
if (reset) {
|
|
pos = 0;
|
|
first = 0;
|
|
stop = 0;
|
|
copy_xpm_area(0, 87, width, 9, x, y);
|
|
}
|
|
|
|
if (stop) {
|
|
return;
|
|
}
|
|
|
|
if ((first == 0) && pos == 0) {
|
|
pos = width;
|
|
first = 1;
|
|
}
|
|
|
|
if (pos < -(dockapp.ctlength)) {
|
|
first = 1;
|
|
pos = width;
|
|
stop = 1;
|
|
return;
|
|
}
|
|
pos -= 2;
|
|
|
|
if (pos > 0) {
|
|
copy_xpm_area(0, 87, pos, 9, x, y); /* clear */
|
|
copy_xpm_area(0, 96, width - pos, 9, x + pos, y);
|
|
} else { /* don't need to clear, already in text */
|
|
copy_xpm_area(abs(pos), 96, width, 9, x, y);
|
|
}
|
|
redraw_window();
|
|
return;
|
|
}
|
|
|
|
void new_window(char *name, int width, int height)
|
|
{
|
|
XpmAttributes attr;
|
|
Pixel fg, bg;
|
|
XGCValues gcval;
|
|
XSizeHints sizehints;
|
|
XClassHint classhint;
|
|
XWMHints wmhints;
|
|
XTextProperty wname;
|
|
|
|
dockapp.width = width;
|
|
dockapp.height = height;
|
|
|
|
sizehints.flags = USSize | USPosition;
|
|
sizehints.x = 0;
|
|
sizehints.y = 0;
|
|
sizehints.width = width;
|
|
sizehints.height = height;
|
|
|
|
fg = BlackPixel(display, DefaultScreen(display));
|
|
bg = WhitePixel(display, DefaultScreen(display));
|
|
|
|
win = XCreateSimpleWindow(display, DefaultRootWindow(display),
|
|
sizehints.x, sizehints.y,
|
|
sizehints.width, sizehints.height, 1, fg,
|
|
bg);
|
|
|
|
iconwin = XCreateSimpleWindow(display, win, sizehints.x, sizehints.y,
|
|
sizehints.width, sizehints.height, 1, fg,
|
|
bg);
|
|
|
|
XSetWMNormalHints(display, win, &sizehints);
|
|
classhint.res_name = name;
|
|
classhint.res_class = name;
|
|
XSetClassHint(display, win, &classhint);
|
|
|
|
#define INPUT_MASK \
|
|
ButtonPressMask \
|
|
| ExposureMask \
|
|
| ButtonReleaseMask \
|
|
| PointerMotionMask \
|
|
| LeaveWindowMask \
|
|
| StructureNotifyMask
|
|
|
|
XSelectInput(display, win, INPUT_MASK);
|
|
XSelectInput(display, iconwin, INPUT_MASK);
|
|
|
|
#undef INPUT_MASk
|
|
|
|
XStringListToTextProperty(&name, 1, &wname);
|
|
XSetWMName(display, win, &wname);
|
|
|
|
gcval.foreground = fg;
|
|
gcval.background = bg;
|
|
gcval.graphics_exposures = 0;
|
|
|
|
dockapp.gc =
|
|
XCreateGC(display, win,
|
|
GCForeground | GCBackground | GCGraphicsExposures,
|
|
&gcval);
|
|
|
|
attr.exactColors = 0;
|
|
attr.alloc_close_colors = 1;
|
|
attr.closeness = 30000;
|
|
attr.valuemask = (XpmExactColors | XpmAllocCloseColors | XpmCloseness);
|
|
if ((XpmCreatePixmapFromData(display, DefaultRootWindow(display),
|
|
master_xpm, &dockapp.pixmap, &dockapp.mask,
|
|
&attr) != XpmSuccess) ||
|
|
(XpmCreatePixmapFromData(display, DefaultRootWindow(display),
|
|
led_on_xpm, &led_on_pixmap, &led_on_mask,
|
|
&attr) != XpmSuccess) ||
|
|
(XpmCreatePixmapFromData(display, DefaultRootWindow(display),
|
|
led_off_xpm, &led_off_pixmap, &led_off_mask,
|
|
&attr) != XpmSuccess)) {
|
|
fputs("Cannot allocate colors for the dockapp pixmaps!\n", stderr);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
XShapeCombineMask(display, win, ShapeBounding, 0, 0, dockapp.mask,
|
|
ShapeSet);
|
|
XShapeCombineMask(display, iconwin, ShapeBounding, 0, 0, dockapp.mask,
|
|
ShapeSet);
|
|
|
|
wmhints.initial_state = WithdrawnState;
|
|
wmhints.icon_window = iconwin;
|
|
wmhints.icon_x = sizehints.x;
|
|
wmhints.icon_y = sizehints.y;
|
|
wmhints.window_group = win;
|
|
wmhints.flags =
|
|
StateHint | IconWindowHint | IconPositionHint | WindowGroupHint;
|
|
XSetWMHints(display, win, &wmhints);
|
|
|
|
hand_cursor = XCreateFontCursor(display, XC_hand2);
|
|
norm_cursor = XCreateFontCursor(display, XC_left_ptr);
|
|
bar_cursor = XCreateFontCursor(display, XC_sb_up_arrow);
|
|
null_cursor = create_null_cursor(display);
|
|
|
|
XMapWindow(display, win);
|
|
}
|
|
|
|
XRRCrtcInfo *crtc_info_by_output_name(char *monitor)
|
|
{
|
|
XRRScreenResources *screen = XRRGetScreenResources(display, DefaultRootWindow(display));
|
|
for (int i = 0; i < screen->noutput; i++) {
|
|
XRROutputInfo *output_info = XRRGetOutputInfo(display, screen, screen->outputs[i]);
|
|
if (!strcmp(monitor, output_info->name)) {
|
|
XRRCrtcInfo *crtc_info = XRRGetCrtcInfo(display, screen, output_info->crtc);
|
|
XRRFreeOutputInfo(output_info);
|
|
XRRFreeScreenResources(screen);
|
|
return crtc_info;
|
|
}
|
|
XRRFreeOutputInfo(output_info);
|
|
}
|
|
XRRFreeScreenResources(screen);
|
|
return NULL;
|
|
}
|
|
|
|
XRRCrtcInfo *crtc_info_by_output_number(int monitor)
|
|
{
|
|
XRRScreenResources *screen = XRRGetScreenResources(display, DefaultRootWindow(display));
|
|
if (monitor >= screen->ncrtc) {
|
|
fprintf(stderr, "wmix:warning: Requested osd monitor number is out of range, clamping\n");
|
|
monitor = screen->ncrtc - 1;
|
|
}
|
|
XRRCrtcInfo *crtc_info = XRRGetCrtcInfo(display, screen, screen->crtcs[monitor]);
|
|
XRRFreeScreenResources(screen);
|
|
return crtc_info;
|
|
}
|
|
|
|
void new_osd(int height)
|
|
{
|
|
Window osd;
|
|
Pixel fg, bg;
|
|
XGCValues gcval;
|
|
GC gc;
|
|
XSizeHints sizehints;
|
|
XSetWindowAttributes xattributes;
|
|
int win_layer = 6;
|
|
XFontStruct *fs = NULL;
|
|
XRRCrtcInfo *crtc_info;
|
|
int width;
|
|
int x;
|
|
int y;
|
|
|
|
if (have_randr) {
|
|
if (config.osd_monitor_name) {
|
|
crtc_info = crtc_info_by_output_name(config.osd_monitor_name);
|
|
if (crtc_info == NULL) {
|
|
fprintf(stderr, "wmix:warning: Requested osd monitor not found, falling back to default\n");
|
|
crtc_info = crtc_info_by_output_number(0);
|
|
}
|
|
}
|
|
else {
|
|
crtc_info = crtc_info_by_output_number(config.osd_monitor_number);
|
|
}
|
|
|
|
width = crtc_info->width - 200;
|
|
x = crtc_info->x + 100;
|
|
y = crtc_info->y + crtc_info->height - 120;
|
|
XRRFreeCrtcInfo(crtc_info);
|
|
if (dockapp.osd &&
|
|
width == dockapp.osd_width &&
|
|
x == dockapp.osd_x &&
|
|
y == dockapp.osd_y) {
|
|
// Nothing important has changed.
|
|
return;
|
|
}
|
|
} else {
|
|
width = DisplayWidth(display, DefaultScreen(display)) - 200;
|
|
x = 100;
|
|
y = DisplayHeight(display, 0) - 120;
|
|
}
|
|
|
|
sizehints.flags = USSize | USPosition;
|
|
sizehints.x = x;
|
|
sizehints.y = y;
|
|
sizehints.width = width;
|
|
sizehints.height = height;
|
|
xattributes.save_under = True;
|
|
xattributes.override_redirect = True;
|
|
xattributes.cursor = None;
|
|
|
|
fg = WhitePixel(display, DefaultScreen(display));
|
|
bg = BlackPixel(display, DefaultScreen(display));
|
|
|
|
if (dockapp.osd)
|
|
XDestroyWindow(display, dockapp.osd);
|
|
osd = XCreateSimpleWindow(display, DefaultRootWindow(display),
|
|
sizehints.x, sizehints.y, width, height,
|
|
0, fg, bg);
|
|
|
|
XSetWMNormalHints(display, osd, &sizehints);
|
|
XChangeWindowAttributes(display, osd, CWSaveUnder | CWOverrideRedirect,
|
|
&xattributes);
|
|
XStoreName(display, osd, "osd");
|
|
XSelectInput(display, osd, ExposureMask);
|
|
|
|
XChangeProperty(display, osd, XInternAtom(display, "_WIN_LAYER", False),
|
|
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&win_layer, 1);
|
|
|
|
gcval.foreground = get_color(display, config.osd_color);
|
|
gcval.background = bg;
|
|
gcval.graphics_exposures = 0;
|
|
|
|
/*
|
|
* -sony-fixed-medium-r-normal--24-170-100-100-c-120-iso8859-1
|
|
* -misc-fixed-medium-r-normal--36-*-75-75-c-*-iso8859-* */
|
|
|
|
/* try our cool scaled 36pt fixed font */
|
|
fs = XLoadQueryFont(display,
|
|
"-misc-fixed-medium-r-normal--36-*-75-75-c-*-iso8859-*");
|
|
|
|
if (fs == NULL) {
|
|
/* they don't have it! */
|
|
/* try our next preferred font (100dpi sony) */
|
|
fprintf(stderr, "Trying alternate font\n");
|
|
fs = XLoadQueryFont(display,
|
|
"-sony-fixed-medium-r-normal--24-*-100-100-c-*-iso8859-*");
|
|
|
|
/* they don't have the sony font either */
|
|
if (fs == NULL) {
|
|
fprintf(stderr, "Trying \"fixed\" font\n");
|
|
fs = XLoadQueryFont(display,
|
|
"fixed");
|
|
/* if they don't have the fixed font, we've got different kind
|
|
* of problems */
|
|
if (fs == NULL) {
|
|
fprintf(stderr, "Your X server is probably broken\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (dockapp.osd_gc)
|
|
XFreeGC(display, dockapp.osd_gc);
|
|
gc =
|
|
XCreateGC(display, osd,
|
|
GCForeground | GCBackground | GCGraphicsExposures,
|
|
&gcval);
|
|
XSetFont(display, gc, fs->fid);
|
|
|
|
dockapp.osd = osd;
|
|
dockapp.osd_gc = gc;
|
|
dockapp.osd_width = width;
|
|
dockapp.osd_x = x;
|
|
dockapp.osd_y = y;
|
|
dockapp.osd_mapped = false;
|
|
}
|
|
|
|
void update_osd(float volume, bool up)
|
|
{
|
|
int i;
|
|
int foo;
|
|
static int bar;
|
|
|
|
if (config.osd) {
|
|
foo = (dockapp.osd_width - 20) * volume / 20.0;
|
|
|
|
if (up) {
|
|
for (i = 1; i <= foo; i++)
|
|
XFillRectangle(display, dockapp.osd, dockapp.osd_gc,
|
|
i * 20, 30, 5, 25);
|
|
} else if (foo < bar) {
|
|
XClearArea(display, dockapp.osd, ((foo+1) * 20), 30,
|
|
((bar-foo) * 20), 25, 1);
|
|
} else if (foo > bar) {
|
|
for (i = (bar > 0 ? bar : 1); i <= foo; i++)
|
|
XFillRectangle(display, dockapp.osd, dockapp.osd_gc,
|
|
i * 20, 30, 5, 25);
|
|
}
|
|
bar = foo;
|
|
}
|
|
}
|
|
|
|
void unmap_osd(void)
|
|
{
|
|
if (config.osd) {
|
|
XUnmapWindow(display, dockapp.osd);
|
|
XFlush(display);
|
|
dockapp.osd_mapped = false;
|
|
}
|
|
}
|
|
|
|
void map_osd(void)
|
|
{
|
|
if (config.osd) {
|
|
XMapRaised(display, dockapp.osd);
|
|
XDrawString(display, dockapp.osd, dockapp.osd_gc, 1, 25,
|
|
mixer_get_channel_name(), strlen(mixer_get_channel_name()));
|
|
update_osd(mixer_get_volume(), true);
|
|
XFlush(display);
|
|
dockapp.osd_mapped = true;
|
|
}
|
|
}
|
|
|
|
bool osd_mapped(void)
|
|
{
|
|
return dockapp.osd_mapped;
|
|
}
|
|
|
|
void set_cursor(int type)
|
|
{
|
|
static int oldtype;
|
|
|
|
if (oldtype == type)
|
|
return;
|
|
|
|
switch (type) {
|
|
case NULL_CURSOR:
|
|
XDefineCursor(display, win, null_cursor);
|
|
XDefineCursor(display, iconwin, null_cursor);
|
|
break;
|
|
case NORMAL_CURSOR:
|
|
XDefineCursor(display, win, norm_cursor);
|
|
XDefineCursor(display, iconwin, norm_cursor);
|
|
break;
|
|
case HAND_CURSOR:
|
|
XDefineCursor(display, win, hand_cursor);
|
|
XDefineCursor(display, iconwin, hand_cursor);
|
|
break;
|
|
case BAR_CURSOR:
|
|
XDefineCursor(display, win, bar_cursor);
|
|
XDefineCursor(display, iconwin, bar_cursor);
|
|
break;
|
|
}
|
|
oldtype = type;
|
|
}
|
|
|
|
/* private */
|
|
static void draw_stereo_led(void)
|
|
{
|
|
if (mixer_is_stereo()) /* stereo capable */
|
|
copy_xpm_area(78, 0, 9, 7, 28, 14); /* light up LCD */
|
|
else /* mono channel */
|
|
copy_xpm_area(78, 7, 9, 7, 28, 14); /* turn off LCD */
|
|
}
|
|
|
|
static void draw_rec_led(void)
|
|
{
|
|
if (mixer_is_rec()) /* record enabled */
|
|
copy_xpm_area(65, 0, 13, 7, 4, 14); /* Light up LCD */
|
|
else /* record disabled */
|
|
copy_xpm_area(65, 7, 13, 7, 4, 14); /* turn off LCD */
|
|
}
|
|
|
|
static void draw_mute_led(void)
|
|
{
|
|
if (mixer_is_muted()) /* mute */
|
|
copy_xpm_area(65, 14, 20, 7, 39, 14); /* light up LCD */
|
|
else /* unmute */
|
|
copy_xpm_area(65, 21, 20, 7, 39, 14); /* turn off LCD */
|
|
}
|
|
|
|
static void draw_percent(void)
|
|
{
|
|
int volume = (int)(mixer_get_volume() * 100);
|
|
|
|
copy_xpm_area(0, 87, 18, 9, 41, 22); /* clear percentage */
|
|
|
|
if (volume < 100) {
|
|
if (volume >= 10)
|
|
copy_xpm_area((volume / 10) * 6, 67, 6, 9, 47, 22);
|
|
copy_xpm_area((volume % 10) * 6, 67, 6, 9, 53, 22);
|
|
} else {
|
|
copy_xpm_area(6, 67, 6, 9, 41, 22);
|
|
copy_xpm_area(0, 67, 6, 9, 47, 22);
|
|
copy_xpm_area(0, 67, 6, 9, 53, 22);
|
|
}
|
|
}
|
|
|
|
static void draw_knob(float volume)
|
|
{
|
|
float bearing, led_x, led_y;
|
|
int led_topleft_x, led_topleft_y;
|
|
Pixmap led_pixmap;
|
|
|
|
bearing = (1.25 * PI) - (1.5 * PI) * volume;
|
|
|
|
led_x = KNOB_CENTER_X + LED_POS_RADIUS * cos(bearing);
|
|
led_y = KNOB_CENTER_Y - LED_POS_RADIUS * sin(bearing);
|
|
|
|
led_topleft_x = (int)(led_x - (LED_WIDTH / 2.0) + 0.5);
|
|
led_topleft_y = (int)(led_y - (LED_HEIGHT / 2.0) + 0.5);
|
|
|
|
/* clear previous knob picture */
|
|
copy_xpm_area(87, 0, 26, 26, 36, 35);
|
|
|
|
if (mixer_is_muted())
|
|
led_pixmap = led_off_pixmap;
|
|
else
|
|
led_pixmap = led_on_pixmap;
|
|
|
|
XCopyArea(display, led_pixmap, dockapp.pixmap, dockapp.gc,
|
|
0, 0, LED_WIDTH, LED_HEIGHT, led_topleft_x, led_topleft_y);
|
|
draw_percent();
|
|
}
|
|
|
|
static void draw_slider(float offset)
|
|
{
|
|
int x = (offset * 50) / 5;
|
|
|
|
copy_xpm_area(65, 45, 27, 20, 4, 40); /* repair region. move */
|
|
copy_xpm_area(65, 29, 7, 15, 14 + x, 43); /* slider */
|
|
}
|
|
|
|
static Cursor create_null_cursor(Display *x_display)
|
|
{
|
|
Pixmap cursor_mask;
|
|
XGCValues gcval;
|
|
GC gc;
|
|
XColor dummy_color;
|
|
Cursor cursor;
|
|
|
|
cursor_mask = XCreatePixmap(x_display, DefaultRootWindow(x_display), 1, 1, 1);
|
|
gcval.function = GXclear;
|
|
gc = XCreateGC(x_display, cursor_mask, GCFunction, &gcval);
|
|
XFillRectangle(x_display, cursor_mask, gc, 0, 0, 1, 1);
|
|
dummy_color.pixel = 0;
|
|
dummy_color.red = 0;
|
|
dummy_color.flags = 04;
|
|
cursor = XCreatePixmapCursor(x_display, cursor_mask, cursor_mask,
|
|
&dummy_color, &dummy_color, 0, 0);
|
|
XFreePixmap(x_display, cursor_mask);
|
|
XFreeGC(x_display, gc);
|
|
|
|
return cursor;
|
|
}
|
|
|
|
unsigned long get_color(Display *display, char *color_name)
|
|
{
|
|
XColor color;
|
|
XWindowAttributes winattr;
|
|
Status status;
|
|
|
|
XGetWindowAttributes(display,
|
|
RootWindow(display, DefaultScreen(display)), &winattr);
|
|
|
|
status = XParseColor(display, winattr.colormap, color_name, &color);
|
|
if (status == 0) {
|
|
fprintf(stderr, "wmix:warning: Could not get color \"%s\" for OSD, falling back to default\n", color_name);
|
|
|
|
if (color_name != default_osd_color)
|
|
status = XParseColor(display, winattr.colormap, default_osd_color, &color);
|
|
if (status == 0)
|
|
return WhitePixel(display, DefaultScreen(display));
|
|
}
|
|
|
|
color.flags = DoRed | DoGreen | DoBlue;
|
|
XAllocColor(display, winattr.colormap, &color);
|
|
|
|
return color.pixel;
|
|
}
|
|
|
|
void ui_rrnotify()
|
|
{
|
|
new_osd(60);
|
|
}
|