Move screen related code into a new file

Since we are adding Xrandr support to allow for automatic dpi detection,
split screen handling code into a new file as part of the effort to
simplify x.c
This commit is contained in:
Nikos Tsipinakis 2017-02-26 16:51:36 +02:00
parent ebea092ddd
commit 0a6b105f4a
5 changed files with 302 additions and 271 deletions

View File

@ -20,6 +20,7 @@
#include "option_parser.h" #include "option_parser.h"
#include "settings.h" #include "settings.h"
#include "x11/x.h" #include "x11/x.h"
#include "x11/screen.h"
#define LENGTH(X) (sizeof X / sizeof X[0]) #define LENGTH(X) (sizeof X / sizeof X[0])

273
src/x11/screen.c Normal file
View File

@ -0,0 +1,273 @@
#include "screen.h"
#include <X11/X.h>
#include <X11/Xatom.h>
#include <X11/Xlib.h>
#include <X11/Xresource.h>
#ifdef XRANDR
#include <X11/extensions/Xrandr.h>
#include <assert.h>
#elif XINERAMA
#include <X11/extensions/Xinerama.h>
#include <assert.h>
#endif
#include <locale.h>
#include <pango/pangocairo.h>
#include <pango/pango-types.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include "src/settings.h"
#include "x.h"
bool dunst_follow_errored = false;
static void x_follow_setup_error_handler(void);
static int x_follow_tear_down_error_handler(void);
static int FollowXErrorHandler(Display *display, XErrorEvent *e);
static Window get_focused_window(void);
static double get_xft_dpi_value()
{
double dpi = 0.0;
XrmInitialize();
char * xRMS = XResourceManagerString(xctx.dpy);
if ( xRMS != NULL ) {
XrmDatabase xDB = XrmGetStringDatabase(xRMS);
char * xrmType;
XrmValue xrmValue;
if ( XrmGetResource(xDB, "Xft.dpi", NULL, &xrmType, &xrmValue))
dpi = strtod(xrmValue.addr, NULL);
}
return dpi;
}
static void set_dpi_value(screen_info * scr, double dpi)
{
if (dpi > 0.0) {
PangoFontMap *font_map = pango_cairo_font_map_get_default();
pango_cairo_font_map_set_resolution((PangoCairoFontMap *) font_map, dpi);
}
#ifdef XRANDR
//fallback to auto-detect method
else {
dpi = (double)scr->dim.h * 25.4 / (double)scr->dim.mmh;
PangoFontMap *font_map = pango_cairo_font_map_get_default();
pango_cairo_font_map_set_resolution((PangoCairoFontMap *) font_map, dpi);
}
#endif
}
#ifdef XRANDR
static int lookup_active_screen(XRRMonitorInfo *info, int n, int x, int y)
{
int ret = -1;
for (int i = 0; i < n; i++) {
if (INRECT(x, y, info[i].x, info[i].y,
info[i].width, info[i].height)) {
ret = i;
}
}
return ret;
}
#elif XINERAMA
static int lookup_active_screen(XineramaScreenInfo * info, int n, int x, int y)
{
int ret = -1;
for (int i = 0; i < n; i++) {
if (INRECT(x, y, info[i].x_org, info[i].y_org,
info[i].width, info[i].height)) {
ret = i;
}
}
return ret;
}
#endif
#ifdef XRANDR
/*
* Select the screen on which the Window
* should be displayed.
*/
static int select_screen(XRRMonitorInfo *info, int n)
#elif XINERAMA
static int select_screen(XineramaScreenInfo * info, int info_len)
#endif
#if defined(XRANDR) || defined(XINERAMA)
{
int ret = 0;
x_follow_setup_error_handler();
if (settings.f_mode == FOLLOW_NONE) {
ret = settings.monitor >=
0 ? settings.monitor : XDefaultScreen(xctx.dpy);
goto sc_cleanup;
} else {
int x, y;
assert(settings.f_mode == FOLLOW_MOUSE
|| settings.f_mode == FOLLOW_KEYBOARD);
Window root =
RootWindow(xctx.dpy, DefaultScreen(xctx.dpy));
if (settings.f_mode == FOLLOW_MOUSE) {
int dummy;
unsigned int dummy_ui;
Window dummy_win;
XQueryPointer(xctx.dpy, root, &dummy_win,
&dummy_win, &x, &y, &dummy,
&dummy, &dummy_ui);
}
if (settings.f_mode == FOLLOW_KEYBOARD) {
Window focused = get_focused_window();
if (focused == 0) {
/* something went wrong. Fallback to default */
ret = settings.monitor >=
0 ? settings.monitor : XDefaultScreen(xctx.dpy);
goto sc_cleanup;
}
Window child_return;
XTranslateCoordinates(xctx.dpy, focused, root,
0, 0, &x, &y, &child_return);
}
ret = lookup_active_screen(info, n, x, y);
if (ret > 0)
goto sc_cleanup;
/* something seems to be wrong. Fallback to default */
ret = settings.monitor >=
0 ? settings.monitor : XDefaultScreen(xctx.dpy);
goto sc_cleanup;
}
sc_cleanup:
x_follow_tear_down_error_handler();
return ret;
}
#endif
/*
* Update the information about the monitor
* geometry.
*/
void x_screen_info(screen_info * scr)
{
#ifdef XRANDR
int n;
XRRMonitorInfo *m;
m = XRRGetMonitors(xctx.dpy, RootWindow(xctx.dpy, DefaultScreen(xctx.dpy)), true, &n);
int screen = select_screen(m, n);
if (screen >= n) {
/* invalid monitor, fallback to default */
screen = 0;
}
scr->dim.x = m[screen].x;
scr->dim.y = m[screen].y;
scr->dim.w = m[screen].width;
scr->dim.h = m[screen].height;
scr->dim.mmh = m[screen].mheight;
XRRFreeMonitors(m);
#elif XINERAMA
int n;
XineramaScreenInfo *info;
if ((info = XineramaQueryScreens(xctx.dpy, &n))) {
int screen = select_screen(info, n);
if (screen >= n) {
/* invalid monitor, fallback to default */
screen = 0;
}
scr->dim.x = info[screen].x_org;
scr->dim.y = info[screen].y_org;
scr->dim.h = info[screen].height;
scr->dim.w = info[screen].width;
XFree(info);
} else
#endif
{
scr->dim.x = 0;
scr->dim.y = 0;
int screen;
if (settings.monitor >= 0)
screen = settings.monitor;
else
screen = DefaultScreen(xctx.dpy);
scr->dim.w = DisplayWidth(xctx.dpy, screen);
scr->dim.h = DisplayHeight(xctx.dpy, screen);
}
//Update dpi
double dpi = 0.0;
dpi = get_xft_dpi_value();
set_dpi_value(scr, dpi);
}
/*
* Return the window that currently has
* the keyboard focus.
*/
static Window get_focused_window(void)
{
Window focused = 0;
Atom type;
int format;
unsigned long nitems, bytes_after;
unsigned char *prop_return = NULL;
Window root = RootWindow(xctx.dpy, DefaultScreen(xctx.dpy));
Atom netactivewindow =
XInternAtom(xctx.dpy, "_NET_ACTIVE_WINDOW", false);
XGetWindowProperty(xctx.dpy, root, netactivewindow, 0L,
sizeof(Window), false, XA_WINDOW,
&type, &format, &nitems, &bytes_after, &prop_return);
if (prop_return) {
focused = *(Window *) prop_return;
XFree(prop_return);
}
return focused;
}
static void x_follow_setup_error_handler(void)
{
dunst_follow_errored = false;
XFlush(xctx.dpy);
XSetErrorHandler(FollowXErrorHandler);
}
static int x_follow_tear_down_error_handler(void)
{
XFlush(xctx.dpy);
XSync(xctx.dpy, false);
XSetErrorHandler(NULL);
return dunst_follow_errored;
}
static int FollowXErrorHandler(Display * display, XErrorEvent * e)
{
dunst_follow_errored = true;
char err_buf[BUFSIZ];
XGetErrorText(display, e->error_code, err_buf, BUFSIZ);
fputs(err_buf, stderr);
fputs("\n", stderr);
return 0;
}

24
src/x11/screen.h Normal file
View File

@ -0,0 +1,24 @@
/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing information) */
#ifndef DUNST_SCREEN_H
#define DUNST_SCREEN_H
#define INRECT(x,y,rx,ry,rw,rh) ((x) >= (rx) && (x) < (rx)+(rw) && (y) >= (ry) && (y) < (ry)+(rh))
typedef struct _dimension_t {
int x;
int y;
unsigned int h;
unsigned int mmh;
unsigned int w;
int mask;
int negative_width;
} dimension_t;
typedef struct _screen_info {
int scr;
dimension_t dim;
} screen_info;
void x_screen_info(screen_info * scr);
#endif

View File

@ -7,13 +7,6 @@
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include <X11/Xutil.h> #include <X11/Xutil.h>
#include <X11/Xresource.h> #include <X11/Xresource.h>
#ifdef XRANDR
#include <X11/extensions/Xrandr.h>
#include <assert.h>
#elif XINERAMA
#include <X11/extensions/Xinerama.h>
#include <assert.h>
#endif
#include <cairo-xlib.h> #include <cairo-xlib.h>
#include <gdk/gdk.h> #include <gdk/gdk.h>
#include <locale.h> #include <locale.h>
@ -31,12 +24,13 @@
#include "src/settings.h" #include "src/settings.h"
#include "src/utils.h" #include "src/utils.h"
#include "screen.h"
#define WIDTH 400 #define WIDTH 400
#define HEIGHT 400 #define HEIGHT 400
xctx_t xctx; xctx_t xctx;
bool dunst_grab_errored = false; bool dunst_grab_errored = false;
bool dunst_follow_errored = false;
typedef struct _cairo_ctx { typedef struct _cairo_ctx {
cairo_status_t status; cairo_status_t status;
@ -59,14 +53,11 @@ typedef struct _colored_layout {
cairo_ctx_t cairo_ctx; cairo_ctx_t cairo_ctx;
/* FIXME refactor setup teardown handlers into one setup and one teardown */ /* FIXME refactor setup teardown handlers into one setup and one teardown */
static void x_follow_setup_error_handler(void);
static int x_follow_tear_down_error_handler(void);
static void x_shortcut_setup_error_handler(void); static void x_shortcut_setup_error_handler(void);
static int x_shortcut_tear_down_error_handler(void); static int x_shortcut_tear_down_error_handler(void);
static void x_win_move(int width, int height); static void x_win_move(int width, int height);
static void setopacity(Window win, unsigned long opacity); static void setopacity(Window win, unsigned long opacity);
static void x_handle_click(XEvent ev); static void x_handle_click(XEvent ev);
static void x_screen_info(screen_info * scr);
static void x_win_setup(void); static void x_win_setup(void);
static color_t x_color_hex_to_double(int hexValue) static color_t x_color_hex_to_double(int hexValue)
@ -902,223 +893,6 @@ static void x_handle_click(XEvent ev)
} }
} }
/*
* Return the window that currently has
* the keyboard focus.
*/
static Window get_focused_window(void)
{
Window focused = 0;
Atom type;
int format;
unsigned long nitems, bytes_after;
unsigned char *prop_return = NULL;
Window root = RootWindow(xctx.dpy, DefaultScreen(xctx.dpy));
Atom netactivewindow =
XInternAtom(xctx.dpy, "_NET_ACTIVE_WINDOW", false);
XGetWindowProperty(xctx.dpy, root, netactivewindow, 0L,
sizeof(Window), false, XA_WINDOW,
&type, &format, &nitems, &bytes_after, &prop_return);
if (prop_return) {
focused = *(Window *) prop_return;
XFree(prop_return);
}
return focused;
}
static double get_xft_dpi_value()
{
double dpi = 0.0;
XrmInitialize();
char * xRMS = XResourceManagerString(xctx.dpy);
if ( xRMS != NULL ) {
XrmDatabase xDB = XrmGetStringDatabase(xRMS);
char * xrmType;
XrmValue xrmValue;
if ( XrmGetResource(xDB, "Xft.dpi", NULL, &xrmType, &xrmValue))
dpi = strtod(xrmValue.addr, NULL);
}
return dpi;
}
static void set_dpi_value(screen_info * scr, double dpi)
{
if (dpi > 0.0) {
PangoFontMap *font_map = pango_cairo_font_map_get_default();
pango_cairo_font_map_set_resolution((PangoCairoFontMap *) font_map, dpi);
}
#ifdef XRANDR
//fallback to auto-detect method
else {
dpi = (double)scr->dim.h * 25.4 / (double)scr->dim.mmh;
PangoFontMap *font_map = pango_cairo_font_map_get_default();
pango_cairo_font_map_set_resolution((PangoCairoFontMap *) font_map, dpi);
}
#endif
}
#ifdef XRANDR
static int lookup_active_screen(XRRMonitorInfo *info, int n, int x, int y)
{
int ret = -1;
for (int i = 0; i < n; i++) {
if (INRECT(x, y, info[i].x, info[i].y,
info[i].width, info[i].height)) {
ret = i;
}
}
return ret;
}
#elif XINERAMA
static int lookup_active_screen(XineramaScreenInfo * info, int n, int x, int y)
{
int ret = -1;
for (int i = 0; i < n; i++) {
if (INRECT(x, y, info[i].x_org, info[i].y_org,
info[i].width, info[i].height)) {
ret = i;
}
}
return ret;
}
#endif
#ifdef XRANDR
/*
* Select the screen on which the Window
* should be displayed.
*/
static int select_screen(XRRMonitorInfo *info, int n)
#elif XINERAMA
static int select_screen(XineramaScreenInfo * info, int info_len)
#endif
#if defined(XRANDR) || defined(XINERAMA)
{
int ret = 0;
x_follow_setup_error_handler();
if (settings.f_mode == FOLLOW_NONE) {
ret = settings.monitor >=
0 ? settings.monitor : XDefaultScreen(xctx.dpy);
goto sc_cleanup;
} else {
int x, y;
assert(settings.f_mode == FOLLOW_MOUSE
|| settings.f_mode == FOLLOW_KEYBOARD);
Window root =
RootWindow(xctx.dpy, DefaultScreen(xctx.dpy));
if (settings.f_mode == FOLLOW_MOUSE) {
int dummy;
unsigned int dummy_ui;
Window dummy_win;
XQueryPointer(xctx.dpy, root, &dummy_win,
&dummy_win, &x, &y, &dummy,
&dummy, &dummy_ui);
}
if (settings.f_mode == FOLLOW_KEYBOARD) {
Window focused = get_focused_window();
if (focused == 0) {
/* something went wrong. Fallback to default */
ret = settings.monitor >=
0 ? settings.monitor : XDefaultScreen(xctx.dpy);
goto sc_cleanup;
}
Window child_return;
XTranslateCoordinates(xctx.dpy, focused, root,
0, 0, &x, &y, &child_return);
}
ret = lookup_active_screen(info, n, x, y);
if (ret > 0)
goto sc_cleanup;
/* something seems to be wrong. Fallback to default */
ret = settings.monitor >=
0 ? settings.monitor : XDefaultScreen(xctx.dpy);
goto sc_cleanup;
}
sc_cleanup:
x_follow_tear_down_error_handler();
return ret;
}
#endif
/*
* Update the information about the monitor
* geometry.
*/
static void x_screen_info(screen_info * scr)
{
#ifdef XRANDR
int n;
XRRMonitorInfo *m;
m = XRRGetMonitors(xctx.dpy, RootWindow(xctx.dpy, DefaultScreen(xctx.dpy)), true, &n);
int screen = select_screen(m, n);
if (screen >= n) {
/* invalid monitor, fallback to default */
screen = 0;
}
scr->dim.x = m[screen].x;
scr->dim.y = m[screen].y;
scr->dim.w = m[screen].width;
scr->dim.h = m[screen].height;
scr->dim.mmh = m[screen].mheight;
XRRFreeMonitors(m);
#elif XINERAMA
int n;
XineramaScreenInfo *info;
if ((info = XineramaQueryScreens(xctx.dpy, &n))) {
int screen = select_screen(info, n);
if (screen >= n) {
/* invalid monitor, fallback to default */
screen = 0;
}
scr->dim.x = info[screen].x_org;
scr->dim.y = info[screen].y_org;
scr->dim.h = info[screen].height;
scr->dim.w = info[screen].width;
XFree(info);
} else
#endif
{
scr->dim.x = 0;
scr->dim.y = 0;
int screen;
if (settings.monitor >= 0)
screen = settings.monitor;
else
screen = DefaultScreen(xctx.dpy);
scr->dim.w = DisplayWidth(xctx.dpy, screen);
scr->dim.h = DisplayHeight(xctx.dpy, screen);
}
//Update dpi
double dpi = 0.0;
dpi = get_xft_dpi_value();
set_dpi_value(scr, dpi);
}
void x_free(void) void x_free(void)
{ {
cairo_surface_destroy(cairo_ctx.surface); cairo_surface_destroy(cairo_ctx.surface);
@ -1365,17 +1139,6 @@ static int GrabXErrorHandler(Display * display, XErrorEvent * e)
return 0; return 0;
} }
static int FollowXErrorHandler(Display * display, XErrorEvent * e)
{
dunst_follow_errored = true;
char err_buf[BUFSIZ];
XGetErrorText(display, e->error_code, err_buf, BUFSIZ);
fputs(err_buf, stderr);
fputs("\n", stderr);
return 0;
}
/* /*
* Setup the Error handler. * Setup the Error handler.
*/ */
@ -1387,14 +1150,6 @@ static void x_shortcut_setup_error_handler(void)
XSetErrorHandler(GrabXErrorHandler); XSetErrorHandler(GrabXErrorHandler);
} }
static void x_follow_setup_error_handler(void)
{
dunst_follow_errored = false;
XFlush(xctx.dpy);
XSetErrorHandler(FollowXErrorHandler);
}
/* /*
* Tear down the Error handler. * Tear down the Error handler.
*/ */
@ -1406,14 +1161,6 @@ static int x_shortcut_tear_down_error_handler(void)
return dunst_grab_errored; return dunst_grab_errored;
} }
static int x_follow_tear_down_error_handler(void)
{
XFlush(xctx.dpy);
XSync(xctx.dpy, false);
XSetErrorHandler(NULL);
return dunst_follow_errored;
}
/* /*
* Grab the given keyboard shortcut. * Grab the given keyboard shortcut.
*/ */

View File

@ -7,25 +7,11 @@
#include <glib.h> #include <glib.h>
#include <stdbool.h> #include <stdbool.h>
#include "screen.h"
#define BUTTONMASK (ButtonPressMask|ButtonReleaseMask) #define BUTTONMASK (ButtonPressMask|ButtonReleaseMask)
#define FONT_HEIGHT_BORDER 2 #define FONT_HEIGHT_BORDER 2
#define DEFFONT "Monospace-11" #define DEFFONT "Monospace-11"
#define INRECT(x,y,rx,ry,rw,rh) ((x) >= (rx) && (x) < (rx)+(rw) && (y) >= (ry) && (y) < (ry)+(rh))
typedef struct _dimension_t {
int x;
int y;
unsigned int h;
unsigned int mmh;
unsigned int w;
int mask;
int negative_width;
} dimension_t;
typedef struct _screen_info {
int scr;
dimension_t dim;
} screen_info;
typedef struct _keyboard_shortcut { typedef struct _keyboard_shortcut {
const char *str; const char *str;