2017-03-26 13:00:19 +02:00
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <X11/Xlib.h>
|
|
|
|
|
#include <X11/Xutil.h>
|
|
|
|
|
#include <X11/cursorfont.h>
|
|
|
|
|
#include <X11/Xproto.h>
|
|
|
|
|
#include <X11/Xresource.h>
|
|
|
|
|
#include <X11/keysym.h>
|
|
|
|
|
#include <X11/Xmu/Error.h>
|
|
|
|
|
#ifdef HAVE_X11_EXTENSIONS_SHAPE_H
|
|
|
|
|
#include <X11/extensions/shape.h>
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef AMIGAOS
|
|
|
|
|
#include <x11/xtrans.h>
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef HAVE_FCNTL_H
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
#endif
|
|
|
|
|
#include <signal.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
2022-02-10 11:11:05 -08:00
|
|
|
#include <stdint.h>
|
2017-03-26 13:00:19 +02:00
|
|
|
#ifdef HAVE_SYS_TIME_H
|
|
|
|
|
#include <sys/time.h>
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef HAVE_SYS_SELECT_H
|
|
|
|
|
#include <sys/select.h>
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef HAVE_SYS_TYPES_H
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef HAVE_UNISTD_H
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef USE_FONTSETS
|
|
|
|
|
#include <locale.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#include "drawinfo.h"
|
|
|
|
|
#include "screen.h"
|
|
|
|
|
#include "icon.h"
|
|
|
|
|
#include "client.h"
|
|
|
|
|
#include "prefs.h"
|
|
|
|
|
#include "module.h"
|
|
|
|
|
#include "icc.h"
|
|
|
|
|
#include "libami.h"
|
|
|
|
|
|
2023-12-21 22:09:25 -08:00
|
|
|
#ifdef AMIGAOS
|
|
|
|
|
#include <pragmas/xlib_pragmas.h>
|
|
|
|
|
extern struct Library *XLibBase;
|
|
|
|
|
|
|
|
|
|
struct timeval {
|
|
|
|
|
long tv_sec;
|
|
|
|
|
long tv_usec;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#define fd_set XTransFdset
|
|
|
|
|
#undef FD_ZERO
|
|
|
|
|
#undef FD_SET
|
|
|
|
|
#define FD_ZERO XTransFdZero
|
|
|
|
|
#define FD_SET XTransFdSet
|
|
|
|
|
#define select XTransSelect
|
|
|
|
|
#endif
|
|
|
|
|
|
2017-03-26 13:00:19 +02:00
|
|
|
#define HYSTERESIS 5
|
|
|
|
|
|
|
|
|
|
typedef struct _DragIcon {
|
|
|
|
|
Icon *icon;
|
|
|
|
|
Window w;
|
|
|
|
|
Pixmap pm;
|
|
|
|
|
int x, y;
|
|
|
|
|
} DragIcon;
|
|
|
|
|
|
|
|
|
|
Display *dpy = NULL;
|
2026-01-31 01:51:39 +00:00
|
|
|
Client *activeclient=NULL, *clickclient=NULL;
|
|
|
|
|
Window clickwindow=None;
|
|
|
|
|
Scrn *menuactive=NULL;
|
|
|
|
|
Bool shape_extn=False;
|
|
|
|
|
char *x_server=NULL;
|
|
|
|
|
char *free_screentitle=NULL;
|
|
|
|
|
XContext client_context, screen_context, icon_context, menu_context, vroot_context;
|
2017-03-26 13:00:19 +02:00
|
|
|
char *progname;
|
|
|
|
|
Cursor wm_curs;
|
2026-01-31 01:51:39 +00:00
|
|
|
|
|
|
|
|
static int signalled=0, forcemoving=0;
|
|
|
|
|
static Time last_icon_click=0, last_double=0;
|
|
|
|
|
static Client *doubleclient=NULL;
|
|
|
|
|
static int initting=0;
|
2017-03-26 13:00:19 +02:00
|
|
|
static int ignore_badwindow=0;
|
2026-01-31 01:51:39 +00:00
|
|
|
static int dblClickTime=1500;
|
2017-03-26 13:00:19 +02:00
|
|
|
static fd_set master_fd_set;
|
|
|
|
|
static int max_fd=0;
|
Make fullscreen work on GTK applications
This commit implements the _NET_SUPPORTING_WM_CHECK property, defined
by the EWMH[1] (Extended Window Management Hints, aka wm-spec), which
indicates that a EWMH-compliant window manager is running.
A GTK application, when set to go fullscreen, first checks root window's
_NET_SUPPORTING_WM_CHECK property to determine whether a EWMH-compliant
window manager is running; and then checks the _NET_SUPPORTED property
to determine the supported protocols.
_NET_SUPPORTED was previously implemented, but _NET_SUPPORTING_WM_CHECK
was not.
This commit also fixes a misconception of the code related to screens.
The code deals with two different, unrelated concepts of screens: the
X11 screen, and the AmiWM screen.
The X11 screen, created by the X server independently of whether a
window manager is running, is a kind of “subdisplay”. A X11 display
structure, which describes a connection to the X server, has one or more
screens. Each X11 screen has its own root window and its own set of
clients that are specific to it, and cannot move to another X11 screen.
The user can even run two different window managers at the same time in
the same display, given that each is run in a different X11 screen.
Usually, there is only one X11 screen.
The _NET_SUPPORTING_WM_CHECK and _NET_SUPPORTED properties must be set
on the root window of each screen that AmiWM is managing. Previously,
however, they were set everytime an AmiWM screen (a totally different
concept) was realized. So, if i had 4 AmiWM screens configured in my
~/.amiwmrc file, setsupports() were called four times, even if i only
have a single X11 screen.
[1]: https://specifications.freedesktop.org/wm/latest/index.html
2026-01-10 02:58:39 +00:00
|
|
|
static Window *checkwins;
|
2026-01-31 01:51:39 +00:00
|
|
|
static int shape_event_base, shape_error_base;
|
|
|
|
|
static int server_grabs=0;
|
|
|
|
|
static unsigned int meta_mask, switch_mask;
|
2017-03-26 13:00:19 +02:00
|
|
|
|
|
|
|
|
static char **main_argv;
|
|
|
|
|
|
|
|
|
|
extern Scrn *mbdclick, *mbdscr;
|
|
|
|
|
|
|
|
|
|
extern void reparent(Client *);
|
|
|
|
|
extern void redraw(Client *, Window);
|
|
|
|
|
extern void redrawclient(Client *);
|
2022-09-05 16:03:55 -07:00
|
|
|
extern void redrawmenubar(Scrn *, Window);
|
2026-01-31 01:51:39 +00:00
|
|
|
extern void resizeclientwindow(Client *c, int, int);
|
2017-03-26 13:00:19 +02:00
|
|
|
extern void gadgetclicked(Client *c, Window w, XEvent *e);
|
|
|
|
|
extern void gadgetunclicked(Client *c, XEvent *e);
|
|
|
|
|
extern void gadgetaborted(Client *c);
|
|
|
|
|
extern void clickenter(void);
|
|
|
|
|
extern void clickleave(void);
|
|
|
|
|
extern void menu_on(void);
|
|
|
|
|
extern void menu_off(void);
|
|
|
|
|
extern void menubar_enter(Window);
|
|
|
|
|
extern void menubar_leave(Window);
|
|
|
|
|
extern void *getitembyhotkey(KeySym);
|
|
|
|
|
extern void menuaction(void *);
|
|
|
|
|
extern Scrn *getscreenbyroot(Window);
|
|
|
|
|
extern void assimilate(Window, int, int);
|
|
|
|
|
extern void deselect_all_icons(Scrn *);
|
|
|
|
|
extern void reparenticon(Icon *, Scrn *, int, int);
|
|
|
|
|
extern void handle_client_message(Client *, XClientMessageEvent *);
|
|
|
|
|
extern void handle_module_input(fd_set *);
|
|
|
|
|
extern int dispatch_event_to_broker(XEvent *, unsigned long, struct module *);
|
|
|
|
|
extern void reshape_frame(Client *c);
|
|
|
|
|
extern void read_rc_file(char *filename, int manage_all);
|
|
|
|
|
extern void init_modules();
|
|
|
|
|
extern void flushmodules();
|
|
|
|
|
extern void raiselowerclient(Client *, int);
|
|
|
|
|
|
|
|
|
|
#ifndef AMIGAOS
|
|
|
|
|
void restart_amiwm()
|
|
|
|
|
{
|
|
|
|
|
flushmodules();
|
|
|
|
|
flushclients();
|
|
|
|
|
XFlush(dpy);
|
|
|
|
|
XCloseDisplay(dpy);
|
|
|
|
|
execvp(main_argv[0], main_argv);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
int handler(Display *d, XErrorEvent *e)
|
|
|
|
|
{
|
|
|
|
|
if (initting && (e->request_code == X_ChangeWindowAttributes) &&
|
|
|
|
|
(e->error_code == BadAccess)) {
|
|
|
|
|
fprintf(stderr, "%s: Another window manager is already running. Not started.\n", progname);
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ignore_badwindow &&
|
|
|
|
|
(e->error_code == BadWindow || e->error_code == BadColor))
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if ((e->error_code == BadMatch && e->request_code == X_ChangeSaveSet) ||
|
|
|
|
|
(e->error_code == BadWindow && e->request_code == X_ChangeProperty) ||
|
|
|
|
|
(e->error_code == BadWindow && e->request_code == X_GetProperty) ||
|
|
|
|
|
(e->error_code == BadWindow && e->request_code == X_GetWindowAttributes) ||
|
|
|
|
|
(e->error_code == BadWindow && e->request_code == X_ChangeWindowAttributes) ||
|
|
|
|
|
(e->error_code == BadDrawable && e->request_code == X_GetGeometry) ||
|
|
|
|
|
(e->error_code == BadWindow && e->request_code == X_SendEvent))
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
XmuPrintDefaultErrorMessage(d, e, stderr);
|
|
|
|
|
|
|
|
|
|
if (initting) {
|
|
|
|
|
fprintf(stderr, "%s: failure during initialisation; aborting\n",
|
|
|
|
|
progname);
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct coevent {
|
|
|
|
|
struct coevent *next;
|
|
|
|
|
struct timeval when;
|
|
|
|
|
void (*what)(void *);
|
|
|
|
|
void *with;
|
|
|
|
|
} *eventlist=NULL;
|
|
|
|
|
|
|
|
|
|
#define FIXUPTV(tv) { \
|
|
|
|
|
while((tv).tv_usec<0) { (tv).tv_usec+=1000000; (tv).tv_sec--; } \
|
|
|
|
|
while((tv).tv_usec>=1000000) { (tv).tv_usec-=1000000; (tv).tv_sec++; } \
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-31 01:51:39 +00:00
|
|
|
static void remove_call_out(void (*what)(void *), void *with)
|
2017-03-26 13:00:19 +02:00
|
|
|
{
|
|
|
|
|
struct coevent *ee, **e=&eventlist;
|
|
|
|
|
|
|
|
|
|
while(*e && ((*e)->what != what || (*e)->with != with))
|
|
|
|
|
e=&(*e)->next;
|
|
|
|
|
if((ee=*e)) {
|
|
|
|
|
*e=(*e)->next;
|
|
|
|
|
free(ee);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef BSD_STYLE_GETTIMEOFDAY
|
|
|
|
|
#define GETTIMEOFDAY(tp) gettimeofday(tp, NULL)
|
|
|
|
|
#else
|
|
|
|
|
#define GETTIMEOFDAY(tp) gettimeofday(tp)
|
|
|
|
|
#endif
|
|
|
|
|
|
2026-01-31 01:51:39 +00:00
|
|
|
static void call_out(int howlong_s, int howlong_u, void (*what)(void *), void *with)
|
2017-03-26 13:00:19 +02:00
|
|
|
{
|
|
|
|
|
struct coevent *ce=malloc(sizeof(struct coevent));
|
|
|
|
|
if(ce) {
|
|
|
|
|
struct coevent **e=&eventlist;
|
|
|
|
|
GETTIMEOFDAY(&ce->when);
|
|
|
|
|
ce->when.tv_sec+=howlong_s;
|
|
|
|
|
ce->when.tv_usec+=howlong_u;
|
|
|
|
|
FIXUPTV(ce->when);
|
|
|
|
|
ce->what=what;
|
|
|
|
|
ce->with=with;
|
|
|
|
|
while(*e && ((*e)->when.tv_sec<ce->when.tv_sec ||
|
|
|
|
|
((*e)->when.tv_sec==ce->when.tv_sec &&
|
|
|
|
|
(*e)->when.tv_usec<=ce->when.tv_usec)))
|
|
|
|
|
e=&(*e)->next;
|
|
|
|
|
ce->next=*e;
|
|
|
|
|
*e=ce;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void call_call_out()
|
|
|
|
|
{
|
|
|
|
|
struct timeval now;
|
|
|
|
|
struct coevent *e;
|
|
|
|
|
GETTIMEOFDAY(&now);
|
|
|
|
|
FIXUPTV(now);
|
|
|
|
|
while((e=eventlist) && (e->when.tv_sec<now.tv_sec ||
|
|
|
|
|
(e->when.tv_sec==now.tv_sec &&
|
|
|
|
|
e->when.tv_usec<=now.tv_usec))) {
|
|
|
|
|
eventlist=e->next;
|
|
|
|
|
(e->what)(e->with);
|
|
|
|
|
free(e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void fill_in_call_out(struct timeval *tv)
|
|
|
|
|
{
|
|
|
|
|
GETTIMEOFDAY(tv);
|
|
|
|
|
tv->tv_sec=eventlist->when.tv_sec-tv->tv_sec;
|
|
|
|
|
tv->tv_usec=eventlist->when.tv_usec-tv->tv_usec;
|
|
|
|
|
FIXUPTV(*tv);
|
|
|
|
|
if(tv->tv_sec<0)
|
|
|
|
|
tv->tv_sec = tv->tv_usec = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void add_fd_to_set(int fd)
|
|
|
|
|
{
|
|
|
|
|
FD_SET(fd, &master_fd_set);
|
|
|
|
|
if(fd>=max_fd)
|
|
|
|
|
max_fd=fd+1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void remove_fd_from_set(int fd)
|
|
|
|
|
{
|
|
|
|
|
FD_CLR(fd, &master_fd_set);
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-31 01:51:39 +00:00
|
|
|
static void lookup_keysyms(Display *dpy, unsigned int *meta_mask,
|
2022-02-10 11:11:05 -08:00
|
|
|
unsigned int *switch_mask)
|
2017-03-26 13:00:19 +02:00
|
|
|
{
|
|
|
|
|
int i,j,k,maxsym,mincode,maxcode;
|
|
|
|
|
XModifierKeymap *map=XGetModifierMapping(dpy);
|
|
|
|
|
KeySym *kp, *kmap;
|
|
|
|
|
unsigned int alt_mask = 0;
|
2022-02-10 11:11:05 -08:00
|
|
|
*meta_mask=0, *switch_mask=0;
|
2017-03-26 13:00:19 +02:00
|
|
|
XDisplayKeycodes(dpy, &mincode, &maxcode);
|
|
|
|
|
kmap=XGetKeyboardMapping(dpy, mincode, maxcode-mincode+1, &maxsym);
|
|
|
|
|
for(i=3; i<8; i++)
|
|
|
|
|
for(j=0; j<map->max_keypermod; j++)
|
|
|
|
|
if(map->modifiermap[i*map->max_keypermod+j] >= mincode)
|
|
|
|
|
for(kp=kmap+(map->modifiermap[i*map->max_keypermod+j]-mincode)*maxsym,
|
|
|
|
|
k=0; k<maxsym; k++)
|
|
|
|
|
switch(*kp++) {
|
|
|
|
|
case XK_Meta_L:
|
|
|
|
|
case XK_Meta_R:
|
2022-02-10 11:11:05 -08:00
|
|
|
*meta_mask|=1<<i;
|
2017-03-26 13:00:19 +02:00
|
|
|
break;
|
|
|
|
|
case XK_Mode_switch:
|
2022-02-10 11:11:05 -08:00
|
|
|
*switch_mask|=1<<i;
|
2017-03-26 13:00:19 +02:00
|
|
|
break;
|
|
|
|
|
case XK_Alt_L:
|
|
|
|
|
case XK_Alt_R:
|
|
|
|
|
alt_mask|=1<<i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
XFree(kmap);
|
|
|
|
|
XFreeModifiermap(map);
|
2022-02-10 11:11:05 -08:00
|
|
|
if(*meta_mask == 0)
|
|
|
|
|
*meta_mask = (alt_mask? alt_mask :
|
|
|
|
|
(*switch_mask? *switch_mask : Mod1Mask));
|
2017-03-26 13:00:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2026-01-31 01:51:39 +00:00
|
|
|
static void restorescreentitle(Scrn *s)
|
2017-03-26 13:00:19 +02:00
|
|
|
{
|
|
|
|
|
(scr=s)->title=s->deftitle;
|
|
|
|
|
XClearWindow(dpy, s->menubar);
|
2022-09-05 16:03:55 -07:00
|
|
|
redrawmenubar(s, s->menubar);
|
2017-03-26 13:00:19 +02:00
|
|
|
if(free_screentitle) {
|
|
|
|
|
free(free_screentitle);
|
|
|
|
|
free_screentitle=NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void wberror(Scrn *s, char *message)
|
|
|
|
|
{
|
|
|
|
|
remove_call_out((void(*)(void *))restorescreentitle, s);
|
|
|
|
|
(scr=s)->title=message;
|
|
|
|
|
XClearWindow(dpy, s->menubar);
|
2022-09-05 16:03:55 -07:00
|
|
|
redrawmenubar(s, s->menubar);
|
2017-03-26 13:00:19 +02:00
|
|
|
XBell(dpy, 100);
|
|
|
|
|
call_out(2, 0, (void(*)(void *))restorescreentitle, s);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void setfocus(Window w)
|
|
|
|
|
{
|
|
|
|
|
if(w == None && prefs.focus != FOC_CLICKTOTYPE)
|
|
|
|
|
w = PointerRoot;
|
|
|
|
|
XSetInputFocus(dpy, w, (prefs.focus==FOC_CLICKTOTYPE? RevertToNone:RevertToPointerRoot), CurrentTime);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void update_clock(void *dontcare);
|
|
|
|
|
|
2026-01-31 01:51:39 +00:00
|
|
|
static void grab_server()
|
2017-03-26 13:00:19 +02:00
|
|
|
{
|
|
|
|
|
if(!server_grabs++)
|
|
|
|
|
XGrabServer(dpy);
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-31 01:51:39 +00:00
|
|
|
static void ungrab_server()
|
2017-03-26 13:00:19 +02:00
|
|
|
{
|
|
|
|
|
if(!--server_grabs) {
|
|
|
|
|
XUngrabServer(dpy);
|
|
|
|
|
if(prefs.titlebarclock) {
|
|
|
|
|
remove_call_out(update_clock, NULL);
|
|
|
|
|
update_clock(NULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-31 01:51:39 +00:00
|
|
|
static void compress_motion(XEvent *event)
|
2017-03-26 13:00:19 +02:00
|
|
|
{
|
2026-01-31 01:51:39 +00:00
|
|
|
if (event->type != MotionNotify)
|
|
|
|
|
return;
|
|
|
|
|
while (XCheckTypedWindowEvent(dpy, event->xmotion.window, MotionNotify, event))
|
|
|
|
|
;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static Bool grab_for_motion(Window w, Window confine, Cursor curs, Time time, int x_root, int y_root)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* To avoid misclicks, only grab for move/resize/etc, if the user has
|
|
|
|
|
* moved the pointer by a given threshold.
|
|
|
|
|
*/
|
|
|
|
|
static const int THRESHOLD = 5;
|
|
|
|
|
int status;
|
|
|
|
|
|
|
|
|
|
XSync(dpy, False);
|
|
|
|
|
status = XGrabPointer(dpy, w, False,
|
|
|
|
|
ButtonPressMask|ButtonReleaseMask|Button1MotionMask,
|
|
|
|
|
GrabModeAsync, GrabModeAsync, confine, None, time);
|
|
|
|
|
if (status == AlreadyGrabbed || status == GrabSuccess) {
|
|
|
|
|
for (;;) {
|
|
|
|
|
XEvent event;
|
|
|
|
|
int dx, dy;
|
|
|
|
|
|
|
|
|
|
XMaskEvent(dpy, ButtonPressMask|ButtonReleaseMask|Button1MotionMask, &event);
|
|
|
|
|
XPutBackEvent(dpy, &event);
|
|
|
|
|
if (event.type != MotionNotify)
|
|
|
|
|
break;
|
|
|
|
|
compress_motion(&event);
|
|
|
|
|
dx = x_root - event.xmotion.x_root;
|
|
|
|
|
dy = y_root - event.xmotion.y_root;
|
|
|
|
|
if (dx*dx + dy*dy > THRESHOLD*THRESHOLD) /* Pythagoras! */
|
|
|
|
|
return True;
|
2017-03-26 13:00:19 +02:00
|
|
|
}
|
|
|
|
|
}
|
2026-01-31 01:51:39 +00:00
|
|
|
XUngrabPointer(dpy, CurrentTime);
|
|
|
|
|
return False;
|
2017-03-26 13:00:19 +02:00
|
|
|
}
|
|
|
|
|
|
2026-01-31 01:51:39 +00:00
|
|
|
static void get_drag_event(XEvent *event)
|
2017-03-26 13:00:19 +02:00
|
|
|
{
|
2026-01-31 01:51:39 +00:00
|
|
|
static const unsigned int DRAG_MASK = ButtonPressMask|ButtonReleaseMask|Button1MotionMask;
|
2017-03-26 13:00:19 +02:00
|
|
|
|
2026-01-31 01:51:39 +00:00
|
|
|
for (;;) {
|
|
|
|
|
fd_set rfds = master_fd_set;
|
|
|
|
|
struct timeval t = {
|
|
|
|
|
.tv_sec = 0,
|
|
|
|
|
.tv_usec = 0,
|
|
|
|
|
};
|
2017-03-26 13:00:19 +02:00
|
|
|
|
2026-01-31 01:51:39 +00:00
|
|
|
while (XCheckMaskEvent(dpy, ExposureMask|DRAG_MASK, event)) {
|
|
|
|
|
Client *c = NULL;
|
|
|
|
|
Icon *i = NULL;
|
|
|
|
|
Scrn *s = NULL;
|
2017-03-26 13:00:19 +02:00
|
|
|
|
2026-01-31 01:51:39 +00:00
|
|
|
if (event->type == MotionNotify)
|
|
|
|
|
compress_motion(event);
|
|
|
|
|
if (event->type != Expose)
|
|
|
|
|
return;
|
|
|
|
|
if (event->xexpose.count)
|
|
|
|
|
continue;
|
|
|
|
|
else if (!XFindContext(dpy, event->xexpose.window, client_context, (XPointer*)&c))
|
|
|
|
|
redraw(c, event->xexpose.window);
|
|
|
|
|
else if (!XFindContext(dpy, event->xexpose.window, icon_context, (XPointer*)&i))
|
|
|
|
|
redrawicon(i, event->xexpose.window);
|
|
|
|
|
else if (!XFindContext(dpy, event->xexpose.window, screen_context, (XPointer*)&s))
|
|
|
|
|
redrawmenubar(s, event->xexpose.window);
|
|
|
|
|
continue;
|
2017-03-26 13:00:19 +02:00
|
|
|
}
|
2026-01-31 01:51:39 +00:00
|
|
|
|
|
|
|
|
if (select(max_fd, &rfds, NULL, NULL, &t) > 0) {
|
|
|
|
|
handle_module_input(&rfds);
|
|
|
|
|
if(FD_ISSET(ConnectionNumber(dpy), &rfds))
|
|
|
|
|
XFlush(dpy);
|
|
|
|
|
continue;
|
2017-03-26 13:00:19 +02:00
|
|
|
}
|
2026-01-31 01:51:39 +00:00
|
|
|
XFlush(dpy);
|
|
|
|
|
rfds = master_fd_set;
|
|
|
|
|
if(eventlist)
|
|
|
|
|
fill_in_call_out(&t);
|
|
|
|
|
if(select(max_fd, &rfds, NULL, NULL, (eventlist? &t:NULL))<0) {
|
|
|
|
|
if (errno != EINTR) {
|
|
|
|
|
perror("select");
|
|
|
|
|
break;
|
2017-03-26 13:00:19 +02:00
|
|
|
}
|
2026-01-31 01:51:39 +00:00
|
|
|
} else {
|
|
|
|
|
call_call_out();
|
|
|
|
|
handle_module_input(&rfds);
|
|
|
|
|
if(FD_ISSET(ConnectionNumber(dpy), &rfds))
|
|
|
|
|
XFlush(dpy);
|
|
|
|
|
}
|
2017-03-26 13:00:19 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-31 01:51:39 +00:00
|
|
|
struct bounding {
|
|
|
|
|
Scrn *scr;
|
|
|
|
|
int x, y, w, h;
|
|
|
|
|
int d_offset;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void draw_bounding(struct bounding *bounding)
|
2017-03-26 13:00:19 +02:00
|
|
|
{
|
2026-01-31 01:51:39 +00:00
|
|
|
int x = bounding->x;
|
|
|
|
|
int y = bounding->y;
|
|
|
|
|
int w = bounding->w;
|
|
|
|
|
int h = bounding->h;
|
2017-03-26 13:00:19 +02:00
|
|
|
|
2026-01-31 01:51:39 +00:00
|
|
|
if (w < 0) {
|
|
|
|
|
x += w;
|
|
|
|
|
w *= -1;
|
|
|
|
|
}
|
|
|
|
|
if (h < 0) {
|
|
|
|
|
y += h;
|
|
|
|
|
h *= -1;
|
|
|
|
|
}
|
|
|
|
|
if (w >= HYSTERESIS || h >=HYSTERESIS) {
|
|
|
|
|
XSetDashes(dpy, bounding->scr->rubbergc, bounding->d_offset,
|
|
|
|
|
(char[]){6}, 1);
|
|
|
|
|
XSetLineAttributes(dpy, bounding->scr->rubbergc, 0, LineOnOffDash,
|
|
|
|
|
CapButt, JoinMiter);
|
|
|
|
|
XDrawRectangle(dpy, bounding->scr->back, bounding->scr->rubbergc,
|
|
|
|
|
x, y, w, h);
|
|
|
|
|
XSetLineAttributes(dpy, bounding->scr->rubbergc, 0, LineSolid,
|
|
|
|
|
CapButt, JoinMiter);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void move_dashes(void *ctx)
|
|
|
|
|
{
|
|
|
|
|
struct bounding *bounding = ctx;
|
|
|
|
|
|
|
|
|
|
call_out(0, 50000, move_dashes, bounding);
|
|
|
|
|
draw_bounding(bounding);
|
|
|
|
|
if (--bounding->d_offset < 0)
|
|
|
|
|
bounding->d_offset = 11;
|
|
|
|
|
draw_bounding(bounding);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void drag_bounding(Scrn *s, Time time, int x_root, int y_root, int x, int y)
|
|
|
|
|
{
|
|
|
|
|
struct bounding bounding = {
|
|
|
|
|
.scr = s,
|
|
|
|
|
.x = x,
|
|
|
|
|
.y = y,
|
|
|
|
|
.w = 0,
|
|
|
|
|
.h = 0,
|
|
|
|
|
.d_offset = 0,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (!grab_for_motion(s->back, None, None, time, x_root, y_root))
|
2017-03-26 13:00:19 +02:00
|
|
|
return;
|
2026-01-31 01:51:39 +00:00
|
|
|
grab_server();
|
|
|
|
|
call_out(0, 0, move_dashes, &bounding);
|
|
|
|
|
for (;;) {
|
|
|
|
|
XEvent event;
|
|
|
|
|
get_drag_event(&event);
|
|
|
|
|
draw_bounding(&bounding);
|
|
|
|
|
if (event.type == ButtonRelease && event.xbutton.button == Button1) {
|
|
|
|
|
remove_call_out(move_dashes, &bounding);
|
|
|
|
|
if (!(event.xbutton.state & ShiftMask))
|
|
|
|
|
deselect_all_icons(s);
|
|
|
|
|
if (bounding.w < 0) {
|
|
|
|
|
bounding.x += bounding.w;
|
|
|
|
|
bounding.w *= -1;
|
|
|
|
|
}
|
|
|
|
|
if (bounding.w < 0) {
|
|
|
|
|
bounding.y += bounding.h;
|
|
|
|
|
bounding.h *= -1;
|
|
|
|
|
}
|
|
|
|
|
if (bounding.w >= HYSTERESIS || bounding.h >= HYSTERESIS) {
|
|
|
|
|
for(Icon *i = s->icons; i != NULL; i = i->next) {
|
|
|
|
|
int bx, by;
|
|
|
|
|
if(i->window && i->mapped &&
|
|
|
|
|
XTranslateCoordinates(dpy, i->parent, s->back, i->x, i->y,
|
|
|
|
|
&bx, &by, &(Window){0}) &&
|
|
|
|
|
bx < bounding.x + bounding.w && bx + i->width>bounding.x &&
|
|
|
|
|
by < bounding.y + bounding.h && by + i->height>bounding.y) {
|
|
|
|
|
selecticon(i);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (event.type == ButtonPress && event.xbutton.button == Button3)
|
|
|
|
|
break;
|
|
|
|
|
if (event.type != MotionNotify)
|
|
|
|
|
continue;
|
|
|
|
|
bounding.w = event.xmotion.x_root - x_root;
|
|
|
|
|
bounding.h = event.xmotion.y_root - y_root;
|
|
|
|
|
draw_bounding(&bounding);
|
|
|
|
|
}
|
2017-03-26 13:00:19 +02:00
|
|
|
|
2026-01-31 01:51:39 +00:00
|
|
|
ungrab_server();
|
|
|
|
|
XUngrabPointer(dpy, CurrentTime);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void drag_move(Client *c, Time time, int x_root, int y_root)
|
|
|
|
|
{
|
|
|
|
|
int x = c->x;
|
|
|
|
|
int y = c->y;
|
|
|
|
|
int dx = x_root - c->x;
|
|
|
|
|
int dy = y_root - c->y;
|
|
|
|
|
|
|
|
|
|
if (!grab_for_motion(c->drag, c->scr->back, None, time, x_root, y_root))
|
|
|
|
|
return;
|
|
|
|
|
grab_server();
|
|
|
|
|
if(!prefs.opaquemove) {
|
|
|
|
|
XDrawRectangle(dpy, c->scr->back, c->scr->rubbergc,
|
|
|
|
|
x, y, c->pwidth-1, c->pheight-1);
|
|
|
|
|
}
|
|
|
|
|
for (;;) {
|
|
|
|
|
XEvent event;
|
|
|
|
|
get_drag_event(&event);
|
|
|
|
|
if(!prefs.opaquemove) {
|
|
|
|
|
XDrawRectangle(dpy, c->scr->back, c->scr->rubbergc,
|
|
|
|
|
x, y, c->pwidth-1, c->pheight-1);
|
|
|
|
|
}
|
|
|
|
|
if (event.type == ButtonRelease && event.xbutton.button == Button1) {
|
|
|
|
|
XMoveWindow(dpy, c->parent, c->x = x, c->y = y);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (event.type == ButtonPress && event.xbutton.button == Button3)
|
|
|
|
|
break;
|
|
|
|
|
if (event.type != MotionNotify)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
x = event.xmotion.x_root - dx;
|
|
|
|
|
y = event.xmotion.y_root - dy;
|
|
|
|
|
if(!forcemoving) {
|
|
|
|
|
if (prefs.forcemove==FM_AUTO &&
|
|
|
|
|
(x + c->pwidth - c->scr->width > (c->pwidth>>2) ||
|
|
|
|
|
y + c->pheight - c->scr->height > (c->pheight>>2) ||
|
|
|
|
|
-x > (c->pwidth>>2) || -y > (c->pheight>>2)))
|
|
|
|
|
forcemoving=1;
|
|
|
|
|
else {
|
|
|
|
|
if (x + c->pwidth > c->scr->width)
|
|
|
|
|
x = c->scr->width-c->pwidth;
|
|
|
|
|
if (y + c->pheight > c->scr->height)
|
|
|
|
|
y = c->scr->height-c->pheight;
|
|
|
|
|
if (x < 0)
|
|
|
|
|
x = 0;
|
|
|
|
|
if (y < 0)
|
|
|
|
|
y = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(prefs.opaquemove) {
|
|
|
|
|
if (y <= -c->scr->bh)
|
|
|
|
|
y = 1 - c->scr->bh;
|
|
|
|
|
XMoveWindow(dpy, c->parent, c->x = x, c->y = y);
|
|
|
|
|
} else {
|
|
|
|
|
XDrawRectangle(dpy, c->scr->back, c->scr->rubbergc,
|
|
|
|
|
x, y, c->pwidth-1, c->pheight-1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
sendconfig(c);
|
|
|
|
|
ungrab_server();
|
|
|
|
|
XUngrabPointer(dpy, CurrentTime);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void drag_screen(Scrn *s, Time time, int x_root, int y_root)
|
|
|
|
|
{
|
|
|
|
|
int y = s->y;
|
|
|
|
|
int dy = y_root - s->y;
|
|
|
|
|
|
|
|
|
|
if (!grab_for_motion(s->menubar, None, None, time, x_root, y_root))
|
|
|
|
|
return;
|
|
|
|
|
for (;;) {
|
|
|
|
|
XEvent event;
|
|
|
|
|
get_drag_event(&event);
|
|
|
|
|
if (event.type == ButtonRelease && event.xbutton.button == Button1) {
|
|
|
|
|
s->y = y;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (event.type == ButtonPress && event.xbutton.button == Button3)
|
|
|
|
|
break;
|
|
|
|
|
if (event.type != MotionNotify)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
y = event.xmotion.y_root - dy;
|
|
|
|
|
#warning TODO: when add multihead, drag screen relative to monitor geometry
|
|
|
|
|
if (y < 0)
|
|
|
|
|
y = 0;
|
|
|
|
|
if (y >= s->height)
|
|
|
|
|
y = s->height - 1;
|
|
|
|
|
XMoveWindow(dpy, s->back, -s->bw, y - s->bw);
|
|
|
|
|
}
|
|
|
|
|
XMoveWindow(dpy, s->back, -s->bw, s->y - s->bw);
|
|
|
|
|
XUngrabPointer(dpy, CurrentTime);
|
|
|
|
|
#ifndef ASSIMILATE_WINDOWS
|
|
|
|
|
scrsendconfig(s);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void drag_icon(Scrn *s, Time time, int x_root, int y_root)
|
|
|
|
|
{
|
|
|
|
|
int nicons = 0;
|
|
|
|
|
DragIcon *dragging = NULL;
|
|
|
|
|
Icon *i;
|
|
|
|
|
|
|
|
|
|
for (i = s->firstselected; i != NULL; i = i->nextselected)
|
|
|
|
|
nicons++;
|
|
|
|
|
if (nicons < 1)
|
|
|
|
|
return;
|
|
|
|
|
dragging = calloc(nicons, sizeof(*dragging));
|
|
|
|
|
if (dragging == NULL) {
|
|
|
|
|
/* is XBell(3) the best way to signal error? */
|
2017-03-26 13:00:19 +02:00
|
|
|
XBell(dpy, 100);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2026-01-31 01:51:39 +00:00
|
|
|
if (!grab_for_motion(s->back, None, None, time, x_root, y_root)) {
|
|
|
|
|
free(dragging);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
for (nicons = 0, i = s->firstselected; i != NULL; i = i->nextselected, nicons++) {
|
|
|
|
|
XWindowAttributes xwa;
|
|
|
|
|
XSetWindowAttributes xswa;
|
2017-03-26 13:00:19 +02:00
|
|
|
|
2026-01-31 01:51:39 +00:00
|
|
|
dragging[nicons].icon = i;
|
2017-03-26 13:00:19 +02:00
|
|
|
XGetWindowAttributes(dpy, i->window, &xwa);
|
2026-01-31 01:51:39 +00:00
|
|
|
XTranslateCoordinates(dpy, i->window, s->root, 0, 0,
|
|
|
|
|
&dragging[nicons].x, &dragging[nicons].y,
|
|
|
|
|
&(Window){0});
|
|
|
|
|
dragging[nicons].x += 4;
|
|
|
|
|
dragging[nicons].y += 4;
|
|
|
|
|
xswa.save_under = True;
|
|
|
|
|
xswa.override_redirect = True;
|
|
|
|
|
if (i->innerwin != None) {
|
2017-03-26 13:00:19 +02:00
|
|
|
XGetWindowAttributes(dpy, i->innerwin, &xwa);
|
2026-01-31 01:51:39 +00:00
|
|
|
xswa.background_pixmap = dragging[nicons].pm = XCreatePixmap(
|
|
|
|
|
dpy, i->innerwin, xwa.width, xwa.height, xwa.depth
|
|
|
|
|
);
|
|
|
|
|
XCopyArea(dpy, i->innerwin, dragging[nicons].pm, s->gc,
|
|
|
|
|
0, 0, xwa.width, xwa.height, 0, 0);
|
2017-03-26 13:00:19 +02:00
|
|
|
} else {
|
2026-01-31 01:51:39 +00:00
|
|
|
if (i->secondpm) {
|
|
|
|
|
xswa.background_pixmap = i->secondpm;
|
|
|
|
|
XGetGeometry(dpy, i->secondpm, &xwa.root, &(int){0}, &(int){0},
|
|
|
|
|
(unsigned int *)&xwa.width, (unsigned int *)&xwa.height,
|
|
|
|
|
&(unsigned int){0}, (unsigned int *)&xwa.depth);
|
|
|
|
|
} else if (i->iconpm) {
|
|
|
|
|
xswa.background_pixmap = i->iconpm;
|
|
|
|
|
XGetGeometry(dpy, i->iconpm, &xwa.root, &(int){0}, &(int){0},
|
|
|
|
|
(unsigned int *)&xwa.width, (unsigned int *)&xwa.height,
|
|
|
|
|
&(unsigned int){0}, (unsigned int *)&xwa.depth);
|
2017-03-26 13:00:19 +02:00
|
|
|
}
|
2026-01-31 01:51:39 +00:00
|
|
|
if (xwa.depth != s->depth) {
|
|
|
|
|
dragging[nicons].pm = XCreatePixmap(dpy, i->window, xwa.width,
|
|
|
|
|
xwa.height, xwa.depth);
|
|
|
|
|
XSetForeground(dpy, s->gc, s->dri.dri_Pens[SHADOWPEN]);
|
|
|
|
|
XSetBackground(dpy, s->gc, s->dri.dri_Pens[BACKGROUNDPEN]);
|
|
|
|
|
XCopyPlane(dpy, xswa.background_pixmap, dragging[nicons].pm,
|
|
|
|
|
s->gc, 0, 0, xwa.width, xwa.height, 0, 0, 1);
|
|
|
|
|
xswa.background_pixmap = dragging[nicons].pm;
|
|
|
|
|
xwa.depth = s->depth;
|
2017-03-26 13:00:19 +02:00
|
|
|
}
|
|
|
|
|
}
|
2026-01-31 01:51:39 +00:00
|
|
|
xswa.colormap = xwa.colormap;
|
|
|
|
|
dragging[nicons].w = XCreateWindow(
|
|
|
|
|
dpy, s->root, dragging[nicons].x, dragging[nicons].y,
|
|
|
|
|
xwa.width, xwa.height, 0, xwa.depth, xwa.class, xwa.visual,
|
|
|
|
|
CWBackPixmap|CWOverrideRedirect|CWSaveUnder|CWColormap, &xswa
|
|
|
|
|
);
|
2017-03-26 13:00:19 +02:00
|
|
|
#ifdef HAVE_XSHAPE
|
2026-01-31 01:51:39 +00:00
|
|
|
if (shape_extn) {
|
|
|
|
|
if (i->innerwin != None) {
|
|
|
|
|
int b_shaped;
|
|
|
|
|
XShapeQueryExtents(
|
|
|
|
|
dpy, i->innerwin,
|
|
|
|
|
&b_shaped, &(int){0}, &(int){0}, &(unsigned){0}, &(unsigned){0},
|
|
|
|
|
&(int){0}, &(int){0}, &(int){0}, &(unsigned){0}, &(unsigned){0}
|
|
|
|
|
);
|
|
|
|
|
if (b_shaped) XShapeCombineShape(
|
|
|
|
|
dpy, dragging[nicons].w, ShapeBounding, 0, 0, i->innerwin,
|
|
|
|
|
ShapeBounding, ShapeSet
|
|
|
|
|
);
|
|
|
|
|
} else if (i->maskpm != None) {
|
|
|
|
|
XShapeCombineMask(
|
|
|
|
|
dpy, dragging[nicons].w, ShapeBounding, 0, 0, i->maskpm, ShapeSet
|
|
|
|
|
);
|
2017-03-26 13:00:19 +02:00
|
|
|
}
|
2022-02-10 11:11:05 -08:00
|
|
|
}
|
2017-03-26 13:00:19 +02:00
|
|
|
#endif
|
2026-01-31 01:51:39 +00:00
|
|
|
XMapRaised(dpy, dragging[nicons].w);
|
2017-03-26 13:00:19 +02:00
|
|
|
}
|
2026-01-31 01:51:39 +00:00
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
|
XEvent event;
|
|
|
|
|
get_drag_event(&event);
|
|
|
|
|
if (event.type == ButtonRelease && event.xbutton.button == Button1) {
|
|
|
|
|
Scrn *s = get_front_scr();
|
|
|
|
|
int wx, wy;
|
|
|
|
|
Window ch;
|
|
|
|
|
Client *c;
|
|
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
|
if (s->root == event.xbutton.root && event.xbutton.y_root >= s->y)
|
|
|
|
|
break;
|
|
|
|
|
s = s->behind;
|
|
|
|
|
if (s == get_front_scr()) {
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (s->deftitle == NULL)
|
|
|
|
|
goto error;
|
|
|
|
|
if (XTranslateCoordinates(dpy, s->root, s->back, x_root, y_root,
|
|
|
|
|
&wx, &wy, &ch) && ch != None) {
|
|
|
|
|
if (XFindContext(dpy, ch, client_context, (void *)&c) ||
|
|
|
|
|
c->scr != s || c->state != NormalState) {
|
|
|
|
|
c = NULL;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
c = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (c != NULL) {
|
|
|
|
|
if (c->module != NULL) {
|
|
|
|
|
XTranslateCoordinates(dpy, s->back, c->window, -4, -4, &wx, &wy, &ch);
|
|
|
|
|
for (int n = 0; n < nicons; n++) {
|
|
|
|
|
dispatch_event_to_broker(mkcmessage(
|
2026-02-19 20:22:50 +00:00
|
|
|
c->window, ATOMS[AMIWM_APPWINDOWMSG],dragging[n].icon->window,
|
2026-01-31 01:51:39 +00:00
|
|
|
dragging[n].x + wx, dragging[n].y + wy
|
|
|
|
|
), 0, c->module);
|
|
|
|
|
}
|
|
|
|
|
goto done;
|
|
|
|
|
} else {
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int n = 0; n < nicons; n++) {
|
|
|
|
|
if (dragging[n].icon->scr != s) {
|
|
|
|
|
dragging[n].icon->mapped = False; /* reparenticon() needs it false */
|
|
|
|
|
reparenticon(dragging[n].icon, s,
|
|
|
|
|
dragging[n].x - 4, dragging[n].y - 4 - s->y);
|
|
|
|
|
} else {
|
|
|
|
|
XMoveWindow(dpy, dragging[n].icon->window,
|
|
|
|
|
dragging[n].icon->x = dragging[n].x - 4,
|
|
|
|
|
dragging[n].icon->y = dragging[n].y - 4 - s->y);
|
|
|
|
|
}
|
|
|
|
|
dragging[n].icon->mapped = True;
|
|
|
|
|
adjusticon(dragging[n].icon);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
if (event.type == ButtonPress && event.xbutton.button == Button3)
|
|
|
|
|
break;
|
|
|
|
|
if (event.type != MotionNotify)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
for (int n = 0; n < nicons; n++) {
|
|
|
|
|
int dx = x_root - dragging[n].x;
|
|
|
|
|
int dy = y_root - dragging[n].y;
|
|
|
|
|
XMoveWindow(dpy, dragging[n].w,
|
|
|
|
|
dragging[n].x = event.xmotion.x_root - dx,
|
|
|
|
|
dragging[n].y = event.xmotion.y_root - dy);
|
|
|
|
|
}
|
|
|
|
|
x_root = event.xmotion.x_root;
|
|
|
|
|
y_root = event.xmotion.y_root;
|
|
|
|
|
}
|
|
|
|
|
error:
|
|
|
|
|
wberror(dragging[0].icon->scr,
|
|
|
|
|
"Icon can't be moved into this window");
|
|
|
|
|
|
|
|
|
|
done:
|
|
|
|
|
for (int n = 0; n < nicons; n++) {
|
|
|
|
|
XDestroyWindow(dpy, dragging[n].w);
|
|
|
|
|
if(dragging[n].pm)
|
|
|
|
|
XFreePixmap(dpy, dragging[n].pm);
|
|
|
|
|
}
|
|
|
|
|
free(dragging);
|
|
|
|
|
XUngrabPointer(dpy, CurrentTime);
|
2017-03-26 13:00:19 +02:00
|
|
|
}
|
|
|
|
|
|
2026-01-31 01:51:39 +00:00
|
|
|
static void drag_resize(Client *c, Time time, int x_root, int y_root)
|
2017-03-26 13:00:19 +02:00
|
|
|
{
|
2026-01-31 01:51:39 +00:00
|
|
|
int w = c->pwidth;
|
|
|
|
|
int h = c->pheight;
|
|
|
|
|
int dx = w - (x_root - c->x);
|
|
|
|
|
int dy = h - (y_root - c->y);
|
|
|
|
|
|
|
|
|
|
if (!grab_for_motion(c->drag, c->scr->back, None, time, x_root, y_root))
|
|
|
|
|
return;
|
|
|
|
|
grab_server();
|
|
|
|
|
if(!prefs.opaqueresize)
|
|
|
|
|
XDrawRectangle(dpy, c->scr->back, c->scr->rubbergc, c->x, c->y, w-1, h-1);
|
|
|
|
|
for (;;) {
|
|
|
|
|
XEvent event;
|
|
|
|
|
get_drag_event(&event);
|
|
|
|
|
if(!prefs.opaqueresize)
|
|
|
|
|
XDrawRectangle(dpy, c->scr->back, c->scr->rubbergc, c->x, c->y, w-1, h-1);
|
|
|
|
|
if (event.type == ButtonRelease && event.xbutton.button == Button1) {
|
|
|
|
|
resizeclientwindow(c, w, h);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (event.type == ButtonPress && event.xbutton.button == Button3)
|
|
|
|
|
break;
|
|
|
|
|
if (event.type != MotionNotify)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
w = event.xmotion.x_root - c->x + dx;
|
|
|
|
|
h = event.xmotion.y_root - c->y + dy;
|
|
|
|
|
if (c->sizehints->width_inc) {
|
|
|
|
|
w -= c->sizehints->base_width + c->framewidth;
|
|
|
|
|
w -= w % c->sizehints->width_inc;
|
|
|
|
|
w += c->sizehints->base_width;
|
|
|
|
|
if (w > c->sizehints->max_width)
|
|
|
|
|
w = c->sizehints->max_width;
|
|
|
|
|
if (w < c->sizehints->min_width)
|
|
|
|
|
w = c->sizehints->min_width;
|
|
|
|
|
w += c->framewidth;
|
|
|
|
|
}
|
|
|
|
|
if (c->sizehints->height_inc) {
|
|
|
|
|
h -= c->sizehints->base_height + c->frameheight;
|
|
|
|
|
h -= h % c->sizehints->height_inc;
|
|
|
|
|
h += c->sizehints->base_height;
|
|
|
|
|
if (h > c->sizehints->max_height)
|
|
|
|
|
h = c->sizehints->max_height;
|
|
|
|
|
if (h < c->sizehints->min_height)
|
|
|
|
|
h = c->sizehints->min_height;
|
|
|
|
|
h += c->frameheight;
|
|
|
|
|
}
|
|
|
|
|
if(prefs.opaqueresize) {
|
|
|
|
|
resizeclientwindow(c, w, h);
|
|
|
|
|
} else {
|
|
|
|
|
XDrawRectangle(dpy, c->scr->back, c->scr->rubbergc, c->x, c->y, w-1, h-1);
|
|
|
|
|
}
|
2017-03-26 13:00:19 +02:00
|
|
|
}
|
2026-01-31 01:51:39 +00:00
|
|
|
sendconfig(c);
|
|
|
|
|
ungrab_server();
|
|
|
|
|
XUngrabPointer(dpy, CurrentTime);
|
2017-03-26 13:00:19 +02:00
|
|
|
}
|
|
|
|
|
|
2026-01-31 01:51:39 +00:00
|
|
|
static void do_icon_double_click(Scrn *scr)
|
2017-03-26 13:00:19 +02:00
|
|
|
{
|
|
|
|
|
Icon *i, *next;
|
|
|
|
|
|
|
|
|
|
for(i=scr->firstselected; i; i=next) {
|
|
|
|
|
next=i->nextselected;
|
|
|
|
|
if(i->module) {
|
2026-02-19 20:22:50 +00:00
|
|
|
dispatch_event_to_broker(mkcmessage(i->window, ATOMS[AMIWM_APPICONMSG], 0),
|
2017-03-26 13:00:19 +02:00
|
|
|
0, i->module);
|
|
|
|
|
} else {
|
2026-02-04 16:12:48 +00:00
|
|
|
deiconify(i);
|
2017-03-26 13:00:19 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-31 01:51:39 +00:00
|
|
|
static void abortfocus()
|
2017-03-26 13:00:19 +02:00
|
|
|
{
|
|
|
|
|
if(activeclient) {
|
|
|
|
|
activeclient->active=False;
|
|
|
|
|
redrawclient(activeclient);
|
|
|
|
|
if(prefs.focus==FOC_CLICKTOTYPE)
|
|
|
|
|
XGrabButton(dpy, Button1, AnyModifier, activeclient->parent,
|
|
|
|
|
True, ButtonPressMask, GrabModeSync, GrabModeAsync,
|
|
|
|
|
None, wm_curs);
|
|
|
|
|
activeclient = NULL;
|
|
|
|
|
}
|
|
|
|
|
setfocus(None);
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-31 01:51:39 +00:00
|
|
|
static RETSIGTYPE sighandler(int sig)
|
2017-03-26 13:00:19 +02:00
|
|
|
{
|
|
|
|
|
signalled=1;
|
|
|
|
|
signal(sig, SIG_IGN);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void instcmap(Colormap c)
|
|
|
|
|
{
|
|
|
|
|
XInstallColormap(dpy, (c == None) ? scr->cmap : c);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void internal_broker(XEvent *e)
|
|
|
|
|
{
|
2022-02-10 11:11:05 -08:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* XXX this is one of the things that the code in module.c
|
|
|
|
|
* is abusing to overload display with some numeric
|
|
|
|
|
* values. Surely there's a better way to do this?
|
|
|
|
|
*/
|
|
|
|
|
uintptr_t event_loc=(uintptr_t)e->xany.display;
|
|
|
|
|
|
2017-03-26 13:00:19 +02:00
|
|
|
e->xany.display=dpy;
|
|
|
|
|
if(event_loc==1) {
|
|
|
|
|
XSendEvent(dpy, e->xany.window, False, 0, e);
|
|
|
|
|
} else switch(e->type) {
|
|
|
|
|
case MappingNotify:
|
|
|
|
|
if(e->xmapping.request==MappingKeyboard ||
|
|
|
|
|
e->xmapping.request==MappingModifier)
|
|
|
|
|
XRefreshKeyboardMapping(&e->xmapping);
|
|
|
|
|
lookup_keysyms(dpy, &meta_mask, &switch_mask);
|
|
|
|
|
break;
|
|
|
|
|
case KeyPress:
|
|
|
|
|
if(e->xkey.state & meta_mask) {
|
|
|
|
|
KeySym ks=XLookupKeysym(&e->xkey,
|
|
|
|
|
((e->xkey.state & ShiftMask)?1:0)+
|
|
|
|
|
((e->xkey.state & switch_mask)?2:0));
|
|
|
|
|
void *item;
|
|
|
|
|
if((item=getitembyhotkey(ks)))
|
|
|
|
|
menuaction(item);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void update_clock(void *dontcare)
|
|
|
|
|
{
|
2022-04-25 19:03:50 -07:00
|
|
|
Scrn *scr;
|
|
|
|
|
|
2017-03-26 13:00:19 +02:00
|
|
|
if(server_grabs)
|
|
|
|
|
return;
|
|
|
|
|
call_out(prefs.titleclockinterval, 0, update_clock, dontcare);
|
2022-04-25 19:03:50 -07:00
|
|
|
|
2022-03-28 20:44:24 -07:00
|
|
|
scr = get_front_scr();
|
2017-03-26 13:00:19 +02:00
|
|
|
do {
|
2022-09-05 16:03:55 -07:00
|
|
|
redrawmenubar(scr, scr->menubar);
|
2017-03-26 13:00:19 +02:00
|
|
|
scr=scr->behind;
|
2022-03-28 20:44:24 -07:00
|
|
|
} while(scr != get_front_scr());
|
2017-03-26 13:00:19 +02:00
|
|
|
}
|
|
|
|
|
|
2026-01-31 01:51:39 +00:00
|
|
|
static void cleanup()
|
2017-03-26 13:00:19 +02:00
|
|
|
{
|
Make fullscreen work on GTK applications
This commit implements the _NET_SUPPORTING_WM_CHECK property, defined
by the EWMH[1] (Extended Window Management Hints, aka wm-spec), which
indicates that a EWMH-compliant window manager is running.
A GTK application, when set to go fullscreen, first checks root window's
_NET_SUPPORTING_WM_CHECK property to determine whether a EWMH-compliant
window manager is running; and then checks the _NET_SUPPORTED property
to determine the supported protocols.
_NET_SUPPORTED was previously implemented, but _NET_SUPPORTING_WM_CHECK
was not.
This commit also fixes a misconception of the code related to screens.
The code deals with two different, unrelated concepts of screens: the
X11 screen, and the AmiWM screen.
The X11 screen, created by the X server independently of whether a
window manager is running, is a kind of “subdisplay”. A X11 display
structure, which describes a connection to the X server, has one or more
screens. Each X11 screen has its own root window and its own set of
clients that are specific to it, and cannot move to another X11 screen.
The user can even run two different window managers at the same time in
the same display, given that each is run in a different X11 screen.
Usually, there is only one X11 screen.
The _NET_SUPPORTING_WM_CHECK and _NET_SUPPORTED properties must be set
on the root window of each screen that AmiWM is managing. Previously,
however, they were set everytime an AmiWM screen (a totally different
concept) was realized. So, if i had 4 AmiWM screens configured in my
~/.amiwmrc file, setsupports() were called four times, even if i only
have a single X11 screen.
[1]: https://specifications.freedesktop.org/wm/latest/index.html
2026-01-10 02:58:39 +00:00
|
|
|
int sc;
|
2017-03-26 13:00:19 +02:00
|
|
|
extern void free_prefs();
|
|
|
|
|
struct coevent *e;
|
|
|
|
|
flushmodules();
|
|
|
|
|
flushclients();
|
2022-03-28 20:44:24 -07:00
|
|
|
scr = get_front_scr();
|
Make fullscreen work on GTK applications
This commit implements the _NET_SUPPORTING_WM_CHECK property, defined
by the EWMH[1] (Extended Window Management Hints, aka wm-spec), which
indicates that a EWMH-compliant window manager is running.
A GTK application, when set to go fullscreen, first checks root window's
_NET_SUPPORTING_WM_CHECK property to determine whether a EWMH-compliant
window manager is running; and then checks the _NET_SUPPORTED property
to determine the supported protocols.
_NET_SUPPORTED was previously implemented, but _NET_SUPPORTING_WM_CHECK
was not.
This commit also fixes a misconception of the code related to screens.
The code deals with two different, unrelated concepts of screens: the
X11 screen, and the AmiWM screen.
The X11 screen, created by the X server independently of whether a
window manager is running, is a kind of “subdisplay”. A X11 display
structure, which describes a connection to the X server, has one or more
screens. Each X11 screen has its own root window and its own set of
clients that are specific to it, and cannot move to another X11 screen.
The user can even run two different window managers at the same time in
the same display, given that each is run in a different X11 screen.
Usually, there is only one X11 screen.
The _NET_SUPPORTING_WM_CHECK and _NET_SUPPORTED properties must be set
on the root window of each screen that AmiWM is managing. Previously,
however, they were set everytime an AmiWM screen (a totally different
concept) was realized. So, if i had 4 AmiWM screens configured in my
~/.amiwmrc file, setsupports() were called four times, even if i only
have a single X11 screen.
[1]: https://specifications.freedesktop.org/wm/latest/index.html
2026-01-10 02:58:39 +00:00
|
|
|
for(sc=0; checkwins!=NULL && sc<ScreenCount(dpy); sc++)
|
|
|
|
|
XDestroyWindow(dpy, checkwins[sc]);
|
|
|
|
|
free(checkwins);
|
2017-03-26 13:00:19 +02:00
|
|
|
while(scr)
|
|
|
|
|
closescreen();
|
|
|
|
|
free_prefs();
|
|
|
|
|
if(dpy) {
|
|
|
|
|
XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
|
|
|
|
|
XFlush(dpy);
|
|
|
|
|
XCloseDisplay(dpy);
|
|
|
|
|
}
|
|
|
|
|
while((e = eventlist)) {
|
|
|
|
|
eventlist = e->next;
|
|
|
|
|
free(e);
|
|
|
|
|
}
|
|
|
|
|
if(x_server)
|
|
|
|
|
free(x_server);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main(int argc, char *argv[])
|
|
|
|
|
{
|
|
|
|
|
int x_fd, sc;
|
|
|
|
|
static Argtype array[3];
|
|
|
|
|
struct RDArgs *ra;
|
|
|
|
|
|
|
|
|
|
#ifdef USE_FONTSETS
|
|
|
|
|
setlocale(LC_CTYPE, "");
|
|
|
|
|
setlocale(LC_TIME, "");
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
main_argv=argv;
|
|
|
|
|
progname=argv[0];
|
|
|
|
|
|
|
|
|
|
atexit(cleanup);
|
|
|
|
|
|
|
|
|
|
memset(array, 0, sizeof(array));
|
|
|
|
|
initargs(argc, argv);
|
|
|
|
|
if(!(ra=ReadArgs((UBYTE *)"RCFILE,DISPLAY/K,SINGLE/S",
|
|
|
|
|
(LONG *)array, NULL))) {
|
|
|
|
|
PrintFault(IoErr(), (UBYTE *)progname);
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
x_server = strdup(XDisplayName(array[1].ptr));
|
|
|
|
|
|
|
|
|
|
XrmInitialize();
|
|
|
|
|
|
|
|
|
|
if(!(dpy = XOpenDisplay(array[1].ptr))) {
|
|
|
|
|
fprintf(stderr, "%s: cannot connect to X server %s\n", progname, x_server);
|
|
|
|
|
FreeArgs(ra);
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(array[1].ptr) {
|
|
|
|
|
char *env=malloc(strlen((char *)array[1].ptr)+10);
|
|
|
|
|
sprintf(env, "DISPLAY=%s", (char *)array[1].ptr);
|
|
|
|
|
putenv(env);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
client_context = XUniqueContext();
|
|
|
|
|
screen_context = XUniqueContext();
|
|
|
|
|
icon_context = XUniqueContext();
|
|
|
|
|
menu_context = XUniqueContext();
|
|
|
|
|
vroot_context = XUniqueContext();
|
|
|
|
|
|
|
|
|
|
wm_curs=XCreateFontCursor(dpy, XC_top_left_arrow);
|
|
|
|
|
|
|
|
|
|
FD_ZERO(&master_fd_set);
|
2022-02-10 11:11:05 -08:00
|
|
|
x_fd=ConnectionNumber(dpy);
|
|
|
|
|
FD_SET(x_fd, &master_fd_set);
|
2017-03-26 13:00:19 +02:00
|
|
|
max_fd=x_fd+1;
|
|
|
|
|
|
|
|
|
|
initting = 1;
|
|
|
|
|
XSetErrorHandler(handler);
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_XSHAPE
|
|
|
|
|
if(XShapeQueryExtension(dpy, &shape_event_base, &shape_error_base))
|
|
|
|
|
shape_extn = 1;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
XSelectInput(dpy, DefaultRootWindow(dpy), SubstructureRedirectMask);
|
|
|
|
|
XSync(dpy, False);
|
|
|
|
|
XSelectInput(dpy, DefaultRootWindow(dpy), NoEventMask);
|
|
|
|
|
|
|
|
|
|
init_modules();
|
|
|
|
|
read_rc_file(array[0].ptr, !array[2].num);
|
|
|
|
|
if( prefs.titleclockinterval < 1 ) prefs.titleclockinterval = 1;
|
|
|
|
|
FreeArgs(ra);
|
|
|
|
|
|
|
|
|
|
if (signal(SIGTERM, sighandler) == SIG_IGN)
|
|
|
|
|
signal(SIGTERM, SIG_IGN);
|
|
|
|
|
if (signal(SIGINT, sighandler) == SIG_IGN)
|
|
|
|
|
signal(SIGINT, SIG_IGN);
|
|
|
|
|
#ifdef SIGHUP
|
|
|
|
|
if (signal(SIGHUP, sighandler) == SIG_IGN)
|
|
|
|
|
signal(SIGHUP, SIG_IGN);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
init_atoms();
|
|
|
|
|
|
|
|
|
|
#ifndef AMIGAOS
|
|
|
|
|
if((fcntl(ConnectionNumber(dpy), F_SETFD, 1)) == -1)
|
|
|
|
|
fprintf(stderr, "%s: child cannot disinherit TCP fd\n", progname);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
lookup_keysyms(dpy, &meta_mask, &switch_mask);
|
|
|
|
|
|
Make fullscreen work on GTK applications
This commit implements the _NET_SUPPORTING_WM_CHECK property, defined
by the EWMH[1] (Extended Window Management Hints, aka wm-spec), which
indicates that a EWMH-compliant window manager is running.
A GTK application, when set to go fullscreen, first checks root window's
_NET_SUPPORTING_WM_CHECK property to determine whether a EWMH-compliant
window manager is running; and then checks the _NET_SUPPORTED property
to determine the supported protocols.
_NET_SUPPORTED was previously implemented, but _NET_SUPPORTING_WM_CHECK
was not.
This commit also fixes a misconception of the code related to screens.
The code deals with two different, unrelated concepts of screens: the
X11 screen, and the AmiWM screen.
The X11 screen, created by the X server independently of whether a
window manager is running, is a kind of “subdisplay”. A X11 display
structure, which describes a connection to the X server, has one or more
screens. Each X11 screen has its own root window and its own set of
clients that are specific to it, and cannot move to another X11 screen.
The user can even run two different window managers at the same time in
the same display, given that each is run in a different X11 screen.
Usually, there is only one X11 screen.
The _NET_SUPPORTING_WM_CHECK and _NET_SUPPORTED properties must be set
on the root window of each screen that AmiWM is managing. Previously,
however, they were set everytime an AmiWM screen (a totally different
concept) was realized. So, if i had 4 AmiWM screens configured in my
~/.amiwmrc file, setsupports() were called four times, even if i only
have a single X11 screen.
[1]: https://specifications.freedesktop.org/wm/latest/index.html
2026-01-10 02:58:39 +00:00
|
|
|
checkwins = calloc(ScreenCount(dpy), sizeof(*checkwins));
|
|
|
|
|
for(sc=0; sc<ScreenCount(dpy); sc++) {
|
|
|
|
|
if(sc==DefaultScreen(dpy) || prefs.manage_all) {
|
|
|
|
|
Window root = RootWindow(dpy, sc);
|
|
|
|
|
checkwins[sc] = XCreateSimpleWindow(dpy, root, 0, 0, 1, 1, 1, 1, 1);
|
|
|
|
|
setsupports(scr->root, checkwins[sc]);
|
|
|
|
|
if(!getscreenbyroot(root)) {
|
2017-03-26 13:00:19 +02:00
|
|
|
char buf[64];
|
|
|
|
|
sprintf(buf, "Screen.%d", sc);
|
Make fullscreen work on GTK applications
This commit implements the _NET_SUPPORTING_WM_CHECK property, defined
by the EWMH[1] (Extended Window Management Hints, aka wm-spec), which
indicates that a EWMH-compliant window manager is running.
A GTK application, when set to go fullscreen, first checks root window's
_NET_SUPPORTING_WM_CHECK property to determine whether a EWMH-compliant
window manager is running; and then checks the _NET_SUPPORTED property
to determine the supported protocols.
_NET_SUPPORTED was previously implemented, but _NET_SUPPORTING_WM_CHECK
was not.
This commit also fixes a misconception of the code related to screens.
The code deals with two different, unrelated concepts of screens: the
X11 screen, and the AmiWM screen.
The X11 screen, created by the X server independently of whether a
window manager is running, is a kind of “subdisplay”. A X11 display
structure, which describes a connection to the X server, has one or more
screens. Each X11 screen has its own root window and its own set of
clients that are specific to it, and cannot move to another X11 screen.
The user can even run two different window managers at the same time in
the same display, given that each is run in a different X11 screen.
Usually, there is only one X11 screen.
The _NET_SUPPORTING_WM_CHECK and _NET_SUPPORTED properties must be set
on the root window of each screen that AmiWM is managing. Previously,
however, they were set everytime an AmiWM screen (a totally different
concept) was realized. So, if i had 4 AmiWM screens configured in my
~/.amiwmrc file, setsupports() were called four times, even if i only
have a single X11 screen.
[1]: https://specifications.freedesktop.org/wm/latest/index.html
2026-01-10 02:58:39 +00:00
|
|
|
openscreen((sc? strdup(buf):"Workbench Screen"), root);
|
2017-03-26 13:00:19 +02:00
|
|
|
}
|
Make fullscreen work on GTK applications
This commit implements the _NET_SUPPORTING_WM_CHECK property, defined
by the EWMH[1] (Extended Window Management Hints, aka wm-spec), which
indicates that a EWMH-compliant window manager is running.
A GTK application, when set to go fullscreen, first checks root window's
_NET_SUPPORTING_WM_CHECK property to determine whether a EWMH-compliant
window manager is running; and then checks the _NET_SUPPORTED property
to determine the supported protocols.
_NET_SUPPORTED was previously implemented, but _NET_SUPPORTING_WM_CHECK
was not.
This commit also fixes a misconception of the code related to screens.
The code deals with two different, unrelated concepts of screens: the
X11 screen, and the AmiWM screen.
The X11 screen, created by the X server independently of whether a
window manager is running, is a kind of “subdisplay”. A X11 display
structure, which describes a connection to the X server, has one or more
screens. Each X11 screen has its own root window and its own set of
clients that are specific to it, and cannot move to another X11 screen.
The user can even run two different window managers at the same time in
the same display, given that each is run in a different X11 screen.
Usually, there is only one X11 screen.
The _NET_SUPPORTING_WM_CHECK and _NET_SUPPORTED properties must be set
on the root window of each screen that AmiWM is managing. Previously,
however, they were set everytime an AmiWM screen (a totally different
concept) was realized. So, if i had 4 AmiWM screens configured in my
~/.amiwmrc file, setsupports() were called four times, even if i only
have a single X11 screen.
[1]: https://specifications.freedesktop.org/wm/latest/index.html
2026-01-10 02:58:39 +00:00
|
|
|
}
|
|
|
|
|
}
|
2017-03-26 13:00:19 +02:00
|
|
|
/*
|
|
|
|
|
if(!front)
|
|
|
|
|
openscreen("Workbench Screen", DefaultRootWindow(dpy));
|
|
|
|
|
*/
|
|
|
|
|
realizescreens();
|
|
|
|
|
|
|
|
|
|
setfocus(None);
|
|
|
|
|
|
|
|
|
|
initting = 0;
|
|
|
|
|
|
|
|
|
|
if(prefs.titlebarclock)
|
|
|
|
|
call_out(0, 0, update_clock, NULL);
|
|
|
|
|
|
|
|
|
|
while(!signalled) {
|
|
|
|
|
fd_set rfds;
|
|
|
|
|
struct timeval t;
|
|
|
|
|
XEvent event;
|
|
|
|
|
Window dummy_root;
|
|
|
|
|
int dummy_x, dummy_y;
|
|
|
|
|
unsigned int dummy_w, dummy_h, dummy_bw, dummy_d;
|
|
|
|
|
|
|
|
|
|
while((!signalled) && QLength(dpy)>0) {
|
|
|
|
|
Client *c; Icon *i;
|
2026-01-31 01:51:39 +00:00
|
|
|
|
2017-03-26 13:00:19 +02:00
|
|
|
XNextEvent(dpy, &event);
|
|
|
|
|
if(!XFindContext(dpy, event.xany.window, client_context,
|
|
|
|
|
(XPointer*)&c)) {
|
|
|
|
|
scr=c->scr;
|
|
|
|
|
} else {
|
|
|
|
|
c = NULL;
|
|
|
|
|
if(XFindContext(dpy, event.xany.window, screen_context,
|
|
|
|
|
(XPointer*)&scr))
|
2022-03-28 20:44:24 -07:00
|
|
|
scr = get_front_scr();
|
2017-03-26 13:00:19 +02:00
|
|
|
}
|
|
|
|
|
if(XFindContext(dpy, event.xany.window, icon_context, (XPointer*)&i))
|
|
|
|
|
i=NULL;
|
|
|
|
|
else
|
|
|
|
|
scr=i->scr;
|
|
|
|
|
switch(event.type) {
|
|
|
|
|
case Expose:
|
|
|
|
|
if(!event.xexpose.count) {
|
|
|
|
|
if(c)
|
|
|
|
|
redraw(c, event.xexpose.window);
|
|
|
|
|
else if(i)
|
|
|
|
|
redrawicon(i, event.xexpose.window);
|
|
|
|
|
else if(scr)
|
2022-09-05 16:03:55 -07:00
|
|
|
redrawmenubar(scr, event.xexpose.window);
|
2017-03-26 13:00:19 +02:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case CreateNotify:
|
2022-03-12 21:04:24 -08:00
|
|
|
|
2017-03-26 13:00:19 +02:00
|
|
|
if(!XFindContext(dpy, event.xcreatewindow.window, client_context,
|
2022-03-12 21:04:24 -08:00
|
|
|
(XPointer *)&c)) {
|
2017-03-26 13:00:19 +02:00
|
|
|
break;
|
2022-03-12 21:04:24 -08:00
|
|
|
}
|
|
|
|
|
|
2017-03-26 13:00:19 +02:00
|
|
|
if(!event.xcreatewindow.override_redirect) {
|
|
|
|
|
if(!(scr=getscreenbyroot(event.xcreatewindow.parent)))
|
2022-03-28 20:44:24 -07:00
|
|
|
scr = get_front_scr();
|
2017-03-26 13:00:19 +02:00
|
|
|
createclient(event.xcreatewindow.window);
|
|
|
|
|
}
|
|
|
|
|
#ifdef ASSIMILATE_WINDOWS
|
|
|
|
|
else if(XFindContext(dpy, event.xcreatewindow.window, screen_context, (XPointer*)&scr)
|
|
|
|
|
&& (scr=getscreenbyroot(event.xcreatewindow.parent))) {
|
|
|
|
|
XGetWindowAttributes(dpy, event.xcreatewindow.window, &attr);
|
|
|
|
|
assimilate(event.xcreatewindow.window, attr.x, attr.y);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
break;
|
|
|
|
|
case DestroyNotify:
|
|
|
|
|
if(!XFindContext(dpy, event.xdestroywindow.window, client_context,
|
|
|
|
|
(XPointer*)&c)) {
|
|
|
|
|
ignore_badwindow = 1;
|
|
|
|
|
rmclient(c);
|
|
|
|
|
XSync(dpy, False);
|
|
|
|
|
ignore_badwindow = 0;
|
|
|
|
|
} else if(!XFindContext(dpy, event.xdestroywindow.window, icon_context,
|
|
|
|
|
(XPointer*)&i)) {
|
|
|
|
|
ignore_badwindow = 1;
|
|
|
|
|
if(i->client)
|
|
|
|
|
i->client->icon=NULL;
|
|
|
|
|
rmicon(i);
|
|
|
|
|
XSync(dpy, False);
|
|
|
|
|
ignore_badwindow = 0;
|
|
|
|
|
} else if(event.xdestroywindow.window)
|
|
|
|
|
XDeleteContext(dpy, event.xdestroywindow.window, screen_context);
|
|
|
|
|
break;
|
|
|
|
|
case UnmapNotify:
|
2023-12-21 22:09:25 -08:00
|
|
|
if(c && c->active && (event.xunmap.window==c->parent) &&
|
|
|
|
|
!(c->fullscreen && c->state == NormalState)) {
|
2017-03-26 13:00:19 +02:00
|
|
|
c->active=False;
|
|
|
|
|
activeclient = NULL;
|
|
|
|
|
redrawclient(c);
|
|
|
|
|
if(prefs.focus == FOC_CLICKTOTYPE)
|
|
|
|
|
XGrabButton(dpy, Button1, AnyModifier, c->parent, True,
|
|
|
|
|
ButtonPressMask, GrabModeSync, GrabModeAsync,
|
|
|
|
|
None, wm_curs);
|
|
|
|
|
if(!menuactive)
|
|
|
|
|
setfocus(None);
|
|
|
|
|
}
|
|
|
|
|
if(c && (event.xunmap.window==c->window)) {
|
|
|
|
|
if((!c->reparenting) && c->parent != c->scr->root) {
|
|
|
|
|
Icon *i=c->icon;
|
|
|
|
|
XUnmapWindow(dpy, c->parent);
|
|
|
|
|
if(i) {
|
|
|
|
|
if(i->labelwin)
|
|
|
|
|
XUnmapWindow(dpy, i->labelwin);
|
|
|
|
|
if(i->window)
|
|
|
|
|
XUnmapWindow(dpy, i->window);
|
|
|
|
|
i->mapped=0;
|
|
|
|
|
deselecticon(i);
|
|
|
|
|
}
|
|
|
|
|
setclientstate(c, WithdrawnState);
|
|
|
|
|
}
|
|
|
|
|
c->reparenting = 0;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case ConfigureNotify:
|
|
|
|
|
if((!XFindContext(dpy, event.xconfigure.window, icon_context,
|
|
|
|
|
(XPointer *)&i)) &&
|
|
|
|
|
event.xconfigure.window == i->window){
|
|
|
|
|
i->x=event.xconfigure.x; i->y=event.xconfigure.y;
|
|
|
|
|
i->width=event.xconfigure.width; i->height=event.xconfigure.height;
|
|
|
|
|
if(i->labelwin) {
|
|
|
|
|
XWindowChanges xwc;
|
|
|
|
|
xwc.x=i->x+(i->width>>1)-(i->labelwidth>>1);
|
|
|
|
|
xwc.y=i->y+i->height+1;
|
|
|
|
|
xwc.sibling=i->window;
|
|
|
|
|
xwc.stack_mode=Below;
|
|
|
|
|
XConfigureWindow(dpy, i->labelwin, CWX|CWY|CWSibling|CWStackMode,
|
|
|
|
|
&xwc);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case ReparentNotify:
|
|
|
|
|
if((!XFindContext(dpy, event.xreparent.window, icon_context,
|
|
|
|
|
(XPointer *)&i)) &&
|
|
|
|
|
event.xreparent.window == i->window){
|
|
|
|
|
i->parent=event.xreparent.parent;
|
|
|
|
|
i->x=event.xreparent.x; i->y=event.xreparent.y;
|
|
|
|
|
if(i->labelwin) {
|
|
|
|
|
XWindowChanges xwc;
|
|
|
|
|
XReparentWindow(dpy, i->labelwin, i->parent,
|
|
|
|
|
i->x+(i->width>>1)-(i->labelwidth>>1),
|
|
|
|
|
i->y+i->height+1);
|
|
|
|
|
xwc.sibling=i->window;
|
|
|
|
|
xwc.stack_mode=Below;
|
|
|
|
|
XConfigureWindow(dpy, i->labelwin, CWSibling|CWStackMode, &xwc);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case CirculateNotify:
|
|
|
|
|
case GravityNotify:
|
|
|
|
|
case NoExpose:
|
|
|
|
|
case GraphicsExpose:
|
|
|
|
|
break;
|
|
|
|
|
case ClientMessage:
|
|
|
|
|
if(c)
|
|
|
|
|
handle_client_message(c, &event.xclient);
|
|
|
|
|
break;
|
|
|
|
|
case ColormapNotify:
|
|
|
|
|
if(event.xcolormap.new && c)
|
|
|
|
|
if(c->colormap!=event.xcolormap.colormap) {
|
|
|
|
|
c->colormap=event.xcolormap.colormap;
|
|
|
|
|
if(c->active)
|
|
|
|
|
instcmap(c->colormap);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case ConfigureRequest:
|
|
|
|
|
if(XFindContext(dpy, event.xconfigurerequest.window, client_context,
|
|
|
|
|
(XPointer*)&c))
|
|
|
|
|
c = NULL;
|
|
|
|
|
if(c && event.xconfigurerequest.window==c->window &&
|
|
|
|
|
c->parent!=c->scr->root) {
|
|
|
|
|
extern void resizeclientwindow(Client *c, int, int);
|
|
|
|
|
if(event.xconfigurerequest.value_mask&CWBorderWidth)
|
|
|
|
|
c->old_bw=event.xconfigurerequest.border_width;
|
|
|
|
|
resizeclientwindow(c, (event.xconfigurerequest.value_mask&CWWidth)?
|
|
|
|
|
event.xconfigurerequest.width+c->framewidth:c->pwidth,
|
|
|
|
|
(event.xconfigurerequest.value_mask&CWHeight)?
|
|
|
|
|
event.xconfigurerequest.height+c->frameheight:c->pheight);
|
|
|
|
|
if((event.xconfigurerequest.value_mask&(CWX|CWY)) &&
|
|
|
|
|
c->state==WithdrawnState)
|
|
|
|
|
XMoveWindow(dpy, c->parent,
|
|
|
|
|
c->x=((event.xconfigurerequest.value_mask&CWX)?
|
|
|
|
|
event.xconfigurerequest.x:c->x),
|
|
|
|
|
c->y=((event.xconfigurerequest.value_mask&CWY)?
|
|
|
|
|
event.xconfigurerequest.y:c->y));
|
|
|
|
|
} else {
|
|
|
|
|
if(!XFindContext(dpy, event.xconfigurerequest.window,
|
|
|
|
|
screen_context, (XPointer *)&scr))
|
|
|
|
|
if((event.xconfigurerequest.y-=scr->y)<0)
|
|
|
|
|
event.xconfigurerequest.y=0;
|
|
|
|
|
XConfigureWindow(dpy, event.xconfigurerequest.window,
|
|
|
|
|
event.xconfigurerequest.value_mask,
|
|
|
|
|
(XWindowChanges *)&event.xconfigurerequest.x);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case CirculateRequest:
|
|
|
|
|
if(XFindContext(dpy, event.xcirculaterequest.window, client_context, (XPointer*)&c))
|
|
|
|
|
if(event.xcirculaterequest.place==PlaceOnTop)
|
|
|
|
|
XRaiseWindow(dpy, event.xcirculaterequest.window);
|
|
|
|
|
else {
|
|
|
|
|
Client *c2;
|
|
|
|
|
Window r,p,*children;
|
|
|
|
|
unsigned int nchildren;
|
|
|
|
|
if(XQueryTree(dpy, scr->back, &r, &p, &children, &nchildren)) {
|
|
|
|
|
int n;
|
|
|
|
|
for(n=0; n<nchildren; n++)
|
|
|
|
|
if((!XFindContext(dpy, children[n], client_context, (XPointer*)&c2)) &&
|
|
|
|
|
children[n]==c2->parent)
|
|
|
|
|
break;
|
|
|
|
|
if(n<nchildren) {
|
|
|
|
|
Window ws[2];
|
|
|
|
|
ws[0]=children[n];
|
|
|
|
|
ws[1]=event.xcirculaterequest.window;
|
|
|
|
|
XRestackWindows(dpy, ws, 2);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
raiselowerclient(c, event.xcirculaterequest.place);
|
|
|
|
|
break;
|
|
|
|
|
case MapRequest:
|
|
|
|
|
if(XFindContext(dpy, event.xmaprequest.window, client_context, (XPointer*)&c)) {
|
|
|
|
|
if(!(scr=getscreenbyroot(event.xmaprequest.parent)))
|
2022-03-28 20:44:24 -07:00
|
|
|
scr = get_front_scr();
|
2017-03-26 13:00:19 +02:00
|
|
|
c=createclient(event.xmaprequest.window);
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
XWMHints *xwmh;
|
|
|
|
|
if(c->parent==c->scr->root && (xwmh=XGetWMHints(dpy, c->window))) {
|
|
|
|
|
if(c->state==WithdrawnState && (xwmh->flags&StateHint)
|
|
|
|
|
&& xwmh->initial_state==IconicState)
|
|
|
|
|
c->state=IconicState;
|
|
|
|
|
XFree(xwmh);
|
|
|
|
|
}
|
|
|
|
|
switch(c->state) {
|
|
|
|
|
case WithdrawnState:
|
|
|
|
|
if(c->parent == c->scr->root)
|
|
|
|
|
reparent(c);
|
|
|
|
|
case NormalState:
|
|
|
|
|
XMapWindow(dpy, c->window);
|
2023-12-21 22:09:25 -08:00
|
|
|
if (!c->fullscreen)
|
|
|
|
|
XMapRaised(dpy, c->parent);
|
2017-03-26 13:00:19 +02:00
|
|
|
setclientstate(c, NormalState);
|
|
|
|
|
break;
|
|
|
|
|
case IconicState:
|
|
|
|
|
if(c->parent == c->scr->root)
|
|
|
|
|
reparent(c);
|
2026-02-04 16:12:48 +00:00
|
|
|
iconify(c);
|
2017-03-26 13:00:19 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case MapNotify:
|
|
|
|
|
if(prefs.focus == FOC_CLICKTOTYPE && c &&
|
|
|
|
|
event.xmap.window == c->parent && c->parent != c->scr->root &&
|
|
|
|
|
(!c->active)) {
|
|
|
|
|
if(activeclient) {
|
|
|
|
|
XGrabButton(dpy, Button1, AnyModifier, activeclient->parent,
|
|
|
|
|
True, ButtonPressMask, GrabModeSync, GrabModeAsync,
|
|
|
|
|
None, wm_curs);
|
|
|
|
|
activeclient->active=False;
|
|
|
|
|
redrawclient(activeclient);
|
|
|
|
|
}
|
|
|
|
|
c->active=True;
|
|
|
|
|
activeclient = c;
|
|
|
|
|
XUngrabButton(dpy, Button1, AnyModifier, c->parent);
|
|
|
|
|
redrawclient(c);
|
|
|
|
|
setfocus(c->window);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case EnterNotify:
|
|
|
|
|
if(menuactive) {
|
|
|
|
|
scr=menuactive;
|
|
|
|
|
menubar_enter(event.xcrossing.window);
|
|
|
|
|
} else if(clickwindow && event.xcrossing.window == clickwindow)
|
|
|
|
|
clickenter();
|
|
|
|
|
else if(c) {
|
|
|
|
|
if((!c->active) && (c->state==NormalState) &&
|
|
|
|
|
prefs.focus!=FOC_CLICKTOTYPE) {
|
|
|
|
|
if(activeclient) {
|
|
|
|
|
activeclient->active=False;
|
|
|
|
|
redrawclient(activeclient);
|
|
|
|
|
}
|
|
|
|
|
setfocus(c->window);
|
|
|
|
|
c->active=True;
|
|
|
|
|
activeclient = c;
|
|
|
|
|
redrawclient(c);
|
|
|
|
|
if(prefs.autoraise && c->parent!=c->scr->root)
|
|
|
|
|
XRaiseWindow(dpy, c->parent);
|
|
|
|
|
}
|
|
|
|
|
if(event.xcrossing.window==c->window)
|
|
|
|
|
instcmap(c->colormap);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case LeaveNotify:
|
|
|
|
|
if(menuactive) {
|
|
|
|
|
scr=menuactive;
|
|
|
|
|
menubar_leave(event.xcrossing.window);
|
|
|
|
|
} else if(clickwindow && event.xcrossing.window == clickwindow)
|
|
|
|
|
clickleave();
|
|
|
|
|
else if(c) {
|
|
|
|
|
if(c->active && event.xcrossing.window==c->parent &&
|
|
|
|
|
event.xcrossing.detail!=NotifyInferior &&
|
|
|
|
|
prefs.focus == FOC_FOLLOWMOUSE) {
|
|
|
|
|
if(!menuactive)
|
|
|
|
|
setfocus(None);
|
|
|
|
|
c->active=False;
|
|
|
|
|
activeclient = NULL;
|
|
|
|
|
instcmap(None);
|
|
|
|
|
redrawclient(c);
|
|
|
|
|
} else if(event.xcrossing.window==c->window &&
|
|
|
|
|
event.xcrossing.detail!=NotifyInferior &&
|
|
|
|
|
event.xcrossing.mode==NotifyNormal)
|
|
|
|
|
instcmap(None);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case ButtonPress:
|
2026-01-31 01:51:39 +00:00
|
|
|
if(clickwindow==None && event.xbutton.button==Button1 && !menuactive) {
|
2017-03-26 13:00:19 +02:00
|
|
|
if(c) {
|
|
|
|
|
if((!c->active) && prefs.focus==FOC_CLICKTOTYPE &&
|
|
|
|
|
(c->state==NormalState)) {
|
|
|
|
|
if(activeclient) {
|
|
|
|
|
activeclient->active=False;
|
|
|
|
|
redrawclient(activeclient);
|
|
|
|
|
XGrabButton(dpy, Button1, AnyModifier, activeclient->parent,
|
|
|
|
|
True, ButtonPressMask, GrabModeSync, GrabModeAsync,
|
|
|
|
|
None, wm_curs);
|
|
|
|
|
}
|
|
|
|
|
setfocus(c->window);
|
|
|
|
|
c->active=True;
|
|
|
|
|
activeclient = c;
|
|
|
|
|
redrawclient(c);
|
|
|
|
|
XUngrabButton(dpy, Button1, AnyModifier, c->parent);
|
|
|
|
|
if(prefs.autoraise && c->parent!=c->scr->root)
|
|
|
|
|
XRaiseWindow(dpy, c->parent);
|
|
|
|
|
}
|
|
|
|
|
if(event.xbutton.window!=c->depth &&
|
2022-02-10 11:11:05 -08:00
|
|
|
event.xbutton.window!=c->window) {
|
2017-03-26 13:00:19 +02:00
|
|
|
if(c==doubleclient && (event.xbutton.time-last_double)<
|
|
|
|
|
dblClickTime) {
|
|
|
|
|
XRaiseWindow(dpy, c->parent);
|
|
|
|
|
} else {
|
|
|
|
|
doubleclient=c;
|
|
|
|
|
last_double=event.xbutton.time;
|
|
|
|
|
}
|
2022-02-10 11:11:05 -08:00
|
|
|
}
|
2017-03-26 13:00:19 +02:00
|
|
|
if(event.xbutton.window==c->drag) {
|
|
|
|
|
forcemoving=(prefs.forcemove==FM_ALWAYS) ||
|
|
|
|
|
(event.xbutton.state & ShiftMask);
|
2026-01-31 01:51:39 +00:00
|
|
|
drag_move(c, event.xbutton.time, event.xbutton.x_root, event.xbutton.y_root);
|
2017-03-26 13:00:19 +02:00
|
|
|
} else if(event.xbutton.window==c->resize)
|
2026-01-31 01:51:39 +00:00
|
|
|
drag_resize(c, event.xbutton.time, event.xbutton.x_root, event.xbutton.y_root);
|
2017-03-26 13:00:19 +02:00
|
|
|
else if(event.xbutton.window==c->window ||
|
|
|
|
|
event.xbutton.window==c->parent)
|
|
|
|
|
;
|
|
|
|
|
else
|
|
|
|
|
gadgetclicked(c, event.xbutton.window, &event);
|
|
|
|
|
} else if(i && event.xbutton.window==i->window) {
|
|
|
|
|
abortfocus();
|
|
|
|
|
if(i->selected && (event.xbutton.time-last_icon_click)<dblClickTime) {
|
|
|
|
|
do_icon_double_click(i->scr);
|
|
|
|
|
} else {
|
|
|
|
|
if(!(event.xbutton.state & ShiftMask))
|
|
|
|
|
deselect_all_icons(i->scr);
|
|
|
|
|
last_icon_click=event.xbutton.time;
|
|
|
|
|
selecticon(i);
|
2026-01-31 01:51:39 +00:00
|
|
|
drag_icon(i->scr, event.xbutton.time, event.xbutton.x_root, event.xbutton.y_root);
|
2017-03-26 13:00:19 +02:00
|
|
|
}
|
|
|
|
|
} else if(scr&&event.xbutton.window==scr->menubardepth) {
|
|
|
|
|
clickwindow=scr->menubardepth;
|
|
|
|
|
mbdclick=mbdscr=scr;
|
2022-09-05 16:03:55 -07:00
|
|
|
redrawmenubar(scr, scr->menubardepth);
|
2017-03-26 13:00:19 +02:00
|
|
|
} else if(scr&&event.xbutton.window==scr->menubar &&
|
|
|
|
|
scr->back!=scr->root) {
|
2026-01-31 01:51:39 +00:00
|
|
|
drag_screen(scr, event.xbutton.time, event.xbutton.x_root, event.xbutton.y_root);
|
|
|
|
|
} else if(scr&&scr->back==event.xbutton.window) {
|
2017-03-26 13:00:19 +02:00
|
|
|
abortfocus();
|
2026-01-31 01:51:39 +00:00
|
|
|
drag_bounding(scr, event.xbutton.time,
|
|
|
|
|
event.xbutton.x_root, event.xbutton.y_root,
|
|
|
|
|
event.xbutton.x, event.xbutton.y);
|
2017-03-26 13:00:19 +02:00
|
|
|
} else ;
|
2026-01-31 01:51:39 +00:00
|
|
|
} else if(event.xbutton.button==3) {
|
|
|
|
|
if(scr&&(scr==mbdscr)&&clickwindow==scr->menubardepth) {
|
2017-03-26 13:00:19 +02:00
|
|
|
mbdclick=NULL;
|
|
|
|
|
clickwindow=None;
|
2022-09-05 16:03:55 -07:00
|
|
|
redrawmenubar(scr, scr->menubardepth);
|
2026-01-31 01:51:39 +00:00
|
|
|
} else if(clickclient) {
|
2017-03-26 13:00:19 +02:00
|
|
|
gadgetaborted(clickclient);
|
2026-01-31 01:51:39 +00:00
|
|
|
} else if(scr&&!menuactive) {
|
2017-03-26 13:00:19 +02:00
|
|
|
menu_on();
|
|
|
|
|
menuactive=scr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(prefs.focus == FOC_CLICKTOTYPE && !menuactive) {
|
|
|
|
|
XSync(dpy,0);
|
|
|
|
|
XAllowEvents(dpy,ReplayPointer,CurrentTime);
|
|
|
|
|
XSync(dpy,0);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case ButtonRelease:
|
|
|
|
|
if(event.xbutton.button==Button1) {
|
2026-01-31 01:51:39 +00:00
|
|
|
if(clickclient)
|
2017-03-26 13:00:19 +02:00
|
|
|
gadgetunclicked(clickclient, &event);
|
|
|
|
|
else if((scr=mbdscr)&& clickwindow==scr->menubardepth) {
|
|
|
|
|
if(mbdclick) {
|
|
|
|
|
mbdclick=NULL;
|
2022-09-05 16:03:55 -07:00
|
|
|
redrawmenubar(scr, scr->menubardepth);
|
2017-03-26 13:00:19 +02:00
|
|
|
screentoback();
|
|
|
|
|
}
|
|
|
|
|
clickwindow=None;
|
|
|
|
|
}
|
|
|
|
|
} else if(event.xbutton.button==Button3 && (scr=menuactive)) {
|
|
|
|
|
menu_off();
|
|
|
|
|
menuactive=NULL;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case MotionNotify:
|
|
|
|
|
break;
|
|
|
|
|
case KeyPress:
|
|
|
|
|
if(!dispatch_event_to_broker(&event, KeyPressMask, modules))
|
|
|
|
|
internal_broker(&event);
|
|
|
|
|
break;
|
|
|
|
|
case KeyRelease:
|
|
|
|
|
if(!dispatch_event_to_broker(&event, KeyPressMask, modules))
|
|
|
|
|
internal_broker(&event);
|
|
|
|
|
break;
|
|
|
|
|
case MappingNotify:
|
|
|
|
|
if(!dispatch_event_to_broker(&event, 0, modules))
|
|
|
|
|
internal_broker(&event);
|
|
|
|
|
break;
|
|
|
|
|
case PropertyNotify:
|
|
|
|
|
if(event.xproperty.atom != None && c &&
|
|
|
|
|
event.xproperty.window==c->window &&
|
|
|
|
|
XGetGeometry(dpy, c->window, &dummy_root, &dummy_x, &dummy_y,
|
|
|
|
|
&dummy_w, &dummy_h, &dummy_bw, &dummy_d))
|
|
|
|
|
propertychange(c, event.xproperty.atom);
|
|
|
|
|
break;
|
|
|
|
|
case FocusOut:
|
|
|
|
|
/* Ignore */
|
|
|
|
|
break;
|
|
|
|
|
case FocusIn:
|
|
|
|
|
if(event.xfocus.detail == NotifyDetailNone &&
|
|
|
|
|
prefs.focus == FOC_CLICKTOTYPE &&
|
|
|
|
|
(scr = getscreenbyroot(event.xfocus.window))) {
|
|
|
|
|
Window w;
|
|
|
|
|
int rt;
|
|
|
|
|
XGetInputFocus(dpy, &w, &rt);
|
|
|
|
|
if(w == None)
|
|
|
|
|
setfocus(scr->inputbox);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
#ifdef HAVE_XSHAPE
|
|
|
|
|
if(shape_extn && event.type == shape_event_base + ShapeNotify) {
|
|
|
|
|
XShapeEvent *s = (XShapeEvent *) &event;
|
|
|
|
|
if(c && s->kind == ShapeBounding) {
|
|
|
|
|
c->shaped = s->shaped;
|
|
|
|
|
reshape_frame(c);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
fprintf(stderr, "%s: got unexpected event type %d.\n",
|
|
|
|
|
progname, event.type);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(signalled) break;
|
|
|
|
|
rfds = master_fd_set;
|
|
|
|
|
t.tv_sec = t.tv_usec = 0;
|
|
|
|
|
if (select(max_fd, &rfds, NULL, NULL, &t) > 0) {
|
|
|
|
|
handle_module_input(&rfds);
|
|
|
|
|
if(FD_ISSET(x_fd, &rfds))
|
|
|
|
|
XPeekEvent(dpy, &event);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if(signalled) break;
|
|
|
|
|
XFlush(dpy);
|
|
|
|
|
rfds = master_fd_set;
|
|
|
|
|
if(eventlist)
|
|
|
|
|
fill_in_call_out(&t);
|
|
|
|
|
if(select(max_fd, &rfds, NULL, NULL, (eventlist? &t:NULL))<0) {
|
|
|
|
|
if (errno != EINTR) {
|
|
|
|
|
perror("select");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
call_call_out();
|
|
|
|
|
handle_module_input(&rfds);
|
|
|
|
|
if(FD_ISSET(x_fd, &rfds))
|
|
|
|
|
XPeekEvent(dpy, &event);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(prefs.titlebarclock)
|
|
|
|
|
remove_call_out(update_clock, NULL);
|
|
|
|
|
|
|
|
|
|
if(signalled)
|
|
|
|
|
fprintf(stderr, "%s: exiting on signal\n", progname);
|
|
|
|
|
|
|
|
|
|
exit(signalled? 0:1);
|
|
|
|
|
}
|
|
|
|
|
|