Krolyxon
Commit 55659ff

Branches

Refs →

nsxivwindow.c

319 lines · 7.9 KB · C

1/* sxiv: window.c
2 * Copyright (c) 2011 Bert Muennich <muennich at informatik.hu-berlin.de>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18
19#include <string.h>
20
21#include <X11/Xutil.h>
22#include <X11/cursorfont.h>
23
24#include "config.h"
25#include "options.h"
26#include "util.h"
27#include "window.h"
28
29static Cursor carrow;
30static Cursor cnone;
31static Cursor chand;
32static Cursor cwatch;
33static GC gc;
34
35Atom wm_delete_win;
36
37void win_set_sizehints(win_t *win) {
38 XSizeHints sizehints;
39
40 if (!win)
41 return;
42
43 sizehints.flags = PMinSize | PMaxSize;
44 sizehints.min_width = win->w;
45 sizehints.max_width = win->w;
46 sizehints.min_height = win->h;
47 sizehints.max_height = win->h;
48 XSetWMNormalHints(win->env.dpy, win->xwin, &sizehints);
49}
50
51void win_open(win_t *win) {
52 win_env_t *e;
53 XClassHint classhint;
54 XColor col;
55 char none_data[] = {0, 0, 0, 0, 0, 0, 0, 0};
56 Pixmap none;
57 int gmask;
58
59 if (!win)
60 return;
61
62 e = &win->env;
63 if (!(e->dpy = XOpenDisplay(NULL)))
64 die("could not open display");
65
66 e->scr = DefaultScreen(e->dpy);
67 e->scrw = DisplayWidth(e->dpy, e->scr);
68 e->scrh = DisplayHeight(e->dpy, e->scr);
69 e->vis = DefaultVisual(e->dpy, e->scr);
70 e->cmap = DefaultColormap(e->dpy, e->scr);
71 e->depth = DefaultDepth(e->dpy, e->scr);
72
73 win->black = BlackPixel(e->dpy, e->scr);
74 win->white = WhitePixel(e->dpy, e->scr);
75
76 if (XAllocNamedColor(e->dpy, DefaultColormap(e->dpy, e->scr), BG_COLOR,
77 &col, &col))
78 win->bgcol = col.pixel;
79 else
80 die("could not allocate color: %s", BG_COLOR);
81 if (XAllocNamedColor(e->dpy, DefaultColormap(e->dpy, e->scr), SEL_COLOR,
82 &col, &col))
83 win->selcol = col.pixel;
84 else
85 die("could not allocate color: %s", BG_COLOR);
86
87 win->pm = 0;
88 win->fullscreen = 0;
89
90 /* determine window offsets, width & height */
91 if (!options->geometry)
92 gmask = 0;
93 else
94 gmask = XParseGeometry(options->geometry, &win->x, &win->y,
95 &win->w, &win->h);
96 if (!(gmask & WidthValue))
97 win->w = WIN_WIDTH;
98 if (win->w > e->scrw)
99 win->w = e->scrw;
100 if (!(gmask & HeightValue))
101 win->h = WIN_HEIGHT;
102 if (win->h > e->scrh)
103 win->h = e->scrh;
104 if (!(gmask & XValue))
105 win->x = (e->scrw - win->w) / 2;
106 else if (gmask & XNegative)
107 win->x += e->scrw - win->w;
108 if (!(gmask & YValue))
109 win->y = (e->scrh - win->h) / 2;
110 else if (gmask & YNegative)
111 win->y += e->scrh - win->h;
112
113 win->xwin = XCreateWindow(e->dpy, RootWindow(e->dpy, e->scr),
114 win->x, win->y, win->w, win->h, 0,
115 e->depth, InputOutput, e->vis, 0, None);
116 if (win->xwin == None)
117 die("could not create window");
118
119 XSelectInput(e->dpy, win->xwin, StructureNotifyMask | KeyPressMask |
120 ButtonPressMask | ButtonReleaseMask | PointerMotionMask);
121
122 carrow = XCreateFontCursor(e->dpy, XC_left_ptr);
123 chand = XCreateFontCursor(e->dpy, XC_fleur);
124 cwatch = XCreateFontCursor(e->dpy, XC_watch);
125
126 if (!XAllocNamedColor(e->dpy, DefaultColormap(e->dpy, e->scr), "black",
127 &col, &col))
128 die("could not allocate color: black");
129 none = XCreateBitmapFromData(e->dpy, win->xwin, none_data, 8, 8);
130 cnone = XCreatePixmapCursor(e->dpy, none, none, &col, &col, 0, 0);
131
132 gc = XCreateGC(e->dpy, win->xwin, 0, None);
133
134 win_set_title(win, "sxiv");
135
136 classhint.res_name = "sxiv";
137 classhint.res_class = "sxiv";
138 XSetClassHint(e->dpy, win->xwin, &classhint);
139
140 if (options->fixed)
141 win_set_sizehints(win);
142
143 XMapWindow(e->dpy, win->xwin);
144 XFlush(e->dpy);
145
146 wm_delete_win = XInternAtom(e->dpy, "WM_DELETE_WINDOW", False);
147 XSetWMProtocols(e->dpy, win->xwin, &wm_delete_win, 1);
148
149 if (options->fullscreen)
150 win_toggle_fullscreen(win);
151}
152
153void win_close(win_t *win) {
154 if (!win)
155 return;
156
157 XFreeCursor(win->env.dpy, carrow);
158 XFreeCursor(win->env.dpy, cnone);
159 XFreeCursor(win->env.dpy, chand);
160 XFreeCursor(win->env.dpy, cwatch);
161
162 XFreeGC(win->env.dpy, gc);
163
164 XDestroyWindow(win->env.dpy, win->xwin);
165 XCloseDisplay(win->env.dpy);
166}
167
168int win_configure(win_t *win, XConfigureEvent *c) {
169 int changed;
170
171 if (!win)
172 return 0;
173
174 changed = win->w != c->width || win->h != c->height;
175
176 win->x = c->x;
177 win->y = c->y;
178 win->w = c->width;
179 win->h = c->height;
180 win->bw = c->border_width;
181
182 return changed;
183}
184
185int win_moveresize(win_t *win, int x, int y, unsigned int w, unsigned int h) {
186 if (!win)
187 return 0;
188
189 x = MAX(0, x);
190 y = MAX(0, y);
191 w = MIN(w, win->env.scrw - 2 * win->bw);
192 h = MIN(h, win->env.scrh - 2 * win->bw);
193
194 if (win->x == x && win->y == y && win->w == w && win->h == h)
195 return 0;
196
197 win->x = x;
198 win->y = y;
199 win->w = w;
200 win->h = h;
201
202 if (options->fixed)
203 win_set_sizehints(win);
204
205 XMoveResizeWindow(win->env.dpy, win->xwin, win->x, win->y, win->w, win->h);
206
207 return 1;
208}
209
210void win_toggle_fullscreen(win_t *win) {
211 XEvent ev;
212 XClientMessageEvent *cm;
213
214 if (!win)
215 return;
216
217 win->fullscreen ^= 1;
218
219 memset(&ev, 0, sizeof(ev));
220 ev.type = ClientMessage;
221
222 cm = &ev.xclient;
223 cm->window = win->xwin;
224 cm->message_type = XInternAtom(win->env.dpy, "_NET_WM_STATE", False);
225 cm->format = 32;
226 cm->data.l[0] = win->fullscreen;
227 cm->data.l[1] = XInternAtom(win->env.dpy, "_NET_WM_STATE_FULLSCREEN", False);
228 cm->data.l[2] = XInternAtom(win->env.dpy, "_NET_WM_STATE_ABOVE", False);
229 cm->data.l[3] = 0;
230
231 XSendEvent(win->env.dpy, DefaultRootWindow(win->env.dpy), False,
232 SubstructureNotifyMask, &ev);
233}
234
235void win_clear(win_t *win) {
236 win_env_t *e;
237 XGCValues gcval;
238
239 if (!win)
240 return;
241
242 e = &win->env;
243 gcval.foreground = win->fullscreen ? win->black : win->bgcol;
244
245 if (win->pm)
246 XFreePixmap(e->dpy, win->pm);
247 win->pm = XCreatePixmap(e->dpy, win->xwin, e->scrw, e->scrh, e->depth);
248
249 XChangeGC(e->dpy, gc, GCForeground, &gcval);
250 XFillRectangle(e->dpy, win->pm, gc, 0, 0, e->scrw, e->scrh);
251}
252
253void win_draw(win_t *win) {
254 if (!win)
255 return;
256
257 XSetWindowBackgroundPixmap(win->env.dpy, win->xwin, win->pm);
258 XClearWindow(win->env.dpy, win->xwin);
259}
260
261void win_draw_rect(win_t *win, Pixmap pm, int x, int y, int w, int h,
262 Bool fill, int lw, unsigned long col) {
263 XGCValues gcval;
264
265 if (!win || !pm)
266 return;
267
268 gcval.line_width = lw;
269 gcval.foreground = col;
270 XChangeGC(win->env.dpy, gc, GCForeground | GCLineWidth, &gcval);
271
272 if (fill)
273 XFillRectangle(win->env.dpy, pm, gc, x, y, w, h);
274 else
275 XDrawRectangle(win->env.dpy, pm, gc, x, y, w, h);
276}
277
278void win_set_title(win_t *win, const char *title) {
279 if (!win)
280 return;
281
282 if (!title)
283 title = "sxiv";
284
285 XStoreName(win->env.dpy, win->xwin, title);
286 XSetIconName(win->env.dpy, win->xwin, title);
287
288 XChangeProperty(win->env.dpy, win->xwin,
289 XInternAtom(win->env.dpy, "_NET_WM_NAME", False),
290 XInternAtom(win->env.dpy, "UTF8_STRING", False), 8,
291 PropModeReplace, (unsigned char *) title, strlen(title));
292 XChangeProperty(win->env.dpy, win->xwin,
293 XInternAtom(win->env.dpy, "_NET_WM_ICON_NAME", False),
294 XInternAtom(win->env.dpy, "UTF8_STRING", False), 8,
295 PropModeReplace, (unsigned char *) title, strlen(title));
296}
297
298void win_set_cursor(win_t *win, win_cur_t cursor) {
299 if (!win)
300 return;
301
302 switch (cursor) {
303 case CURSOR_NONE:
304 XDefineCursor(win->env.dpy, win->xwin, cnone);
305 break;
306 case CURSOR_HAND:
307 XDefineCursor(win->env.dpy, win->xwin, chand);
308 break;
309 case CURSOR_WATCH:
310 XDefineCursor(win->env.dpy, win->xwin, cwatch);
311 break;
312 case CURSOR_ARROW:
313 default:
314 XDefineCursor(win->env.dpy, win->xwin, carrow);
315 break;
316 }
317
318 XFlush(win->env.dpy);
319}