From eeb32e7efcca46cc7307c97710c88161ae288873 Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Tue, 10 Oct 2023 16:25:49 +0300 Subject: [PATCH 01/67] ProcessManager (_terminateApplication): cleanup Controller (applicationShouldTerminate): simplify and refactor code; activate Workspace if some application terminated logout or poweroff ptocess. --- .../Workspace/Processes/ProcessManager.m | 38 ++++--------------- 1 file changed, 8 insertions(+), 30 deletions(-) diff --git a/Applications/Workspace/Processes/ProcessManager.m b/Applications/Workspace/Processes/ProcessManager.m index 0e66af168..0d59df59d 100644 --- a/Applications/Workspace/Processes/ProcessManager.m +++ b/Applications/Workspace/Processes/ProcessManager.m @@ -261,7 +261,7 @@ - (void)sendSignal:(int)signal toApplication:(NSDictionary *)appInfo for (NSNumber *pid in pidList) { // If PID is '-1' let window manager kill that app. if ([pid intValue] != -1) { - NSLog(@"Sending INT signal to %i", [pid intValue]); + NSDebugLLog(@"Workspace", @"Sending signal %i to %i", signal, [pid intValue]); kill([pid intValue], signal); } @@ -289,45 +289,27 @@ - (BOOL)_terminateApplication:(NSDictionary *)appInfo return YES; } - NSLog(@"Terminating - %@", _appName); + NSDebugLLog(@"Workspace", @"Terminating - %@", _appName); _app = [NSConnection rootProxyForConnectionWithRegisteredName:_appName host:@""]; if (_app == nil) { - NSLog(@"Connection to %@ failed. Removing from list of known applications", _appName); + NSDebugLLog(@"Workspace", @"Connection to %@ failed. Removing from list of known applications", _appName); [applications removeObject:appInfo]; return YES; } - // NSLog(@"_terminateApplication - performSelector:withObject:"); - // id terminateObj = [_app performSelector:@selector(applicationShouldTerminate:) - // withObject:NSApp]; - // NSApplicationTerminateReply shouldTerminate = NSTerminateNow; - // if ([_app respondsToSelector:@selector(applicationShouldTerminate:)]) { - // NSLog(@"_terminateApplication - applicationShouldTerminate:"); - // shouldTerminate = ([_app applicationShouldTerminate:NSApp] & 0xff); - // NSLog(@"_terminateApplication: %@ - %li", terminateObj ? [terminateObj className] : terminateObj, shouldTerminate); - // } - - // // NSApplicationTerminateReply shouldTerminate = ([_app applicationShouldTerminate:nil] & 0xff); - // if (shouldTerminate != NSTerminateNow) { - // NSLog(@"Application '%@' is not terminated!", _appName); - // return NO; - // } - - // NSLog(@"Application '%@' should terminate: %li", _appName, shouldTerminate); - // [[_app connectionForProxy] invalidate]; - // [self sendSignal:SIGINT toApplication:appInfo]; - - // libobjc2 prints out info to console all exception (even catched). - // I've switched to singal-based (above) to analyze and fix other cases with exceptions. @try { - [_app terminate:nil]; + [_app terminate:NSApp]; } @catch (NSException *e) { // application terminated -- remove app from launched apps list [applications removeObject:appInfo]; [[_app connectionForProxy] invalidate]; + // libobjc2 prints out info to console all exception (even catched). + NSDebugLLog(@"Workspace", @"Application %@ was terminated. Ignore ObjC runtime exception - it's catched.", _appName); return YES; } + [[_app connectionForProxy] invalidate]; + return NO; } @@ -362,10 +344,6 @@ - (BOOL)terminateAllApps break; } - // while ([applications count] > 1 && _workspaceQuitting != NO) { - // NSDebugLLog(@"Workspace", @"Waiting for applications to terminate..."); - // [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; - // } NSDebugLLog(@"Workspace", @"Terminating of runnig apps completed!"); [_appsCopy release]; From 019fb5cec7d2efdcfe96563e79bae6e1bff03745 Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Tue, 10 Oct 2023 16:55:38 +0300 Subject: [PATCH 02/67] add missed Controller changes. --- Applications/Workspace/Controller.m | 55 ++++++++++++++--------------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/Applications/Workspace/Controller.m b/Applications/Workspace/Controller.m index b56c60293..269b5777a 100644 --- a/Applications/Workspace/Controller.m +++ b/Applications/Workspace/Controller.m @@ -761,56 +761,45 @@ - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sende case NSAlertDefaultReturn: // Log Out { [[NSApp mainMenu] close]; - _isQuitting = YES; - if ([procManager terminateAllBGOperations] == NO) { - _isQuitting = NO; - terminateReply = NSTerminateCancel; - } + _isQuitting = [procManager terminateAllBGOperations]; if (_isQuitting != NO) { // Save running applications [self _saveRunningApplications]; - - if ([procManager terminateAllApps] == NO) { - NXTRunAlertPanel(_(@"Log Out"), _(@"Some application terminate power off process."), - _(@"Dismiss"), nil, nil); - _isQuitting = NO; - terminateReply = NSTerminateCancel; + _isQuitting = [procManager terminateAllApps]; + if (_isQuitting == NO) { + NXTRunAlertPanel(_(@"Log Out"), _(@"'%@' application request to cancel Log Out."), _(@"Dismiss"), nil, nil, + [self activeApplication][@"NSApplicationName"]); } } - if (_isQuitting != NO) { + + if (_isQuitting == NO) { + terminateReply = NSTerminateCancel; + } else { // Close Workspace windows, hide Dock, quit WM [self _finishTerminateProcess]; terminateReply = NSTerminateNow; ws_quit_code = WSLogoutOnQuit; - } else { - [[NSApp mainMenu] display]; } } break; case NSAlertAlternateReturn: // Power off { [[NSApp mainMenu] close]; - _isQuitting = YES; - if ([procManager terminateAllBGOperations] == NO) { - _isQuitting = NO; - terminateReply = NSTerminateCancel; - } + _isQuitting = [procManager terminateAllBGOperations]; if (_isQuitting != NO) { // Save running applications [self _saveRunningApplications]; - - if ([procManager terminateAllApps] == NO) { - NXTRunAlertPanel(_(@"Power Off"), _(@"Some application terminate power off process."), - _(@"Dismiss"), nil, nil); - _isQuitting = NO; - terminateReply = NSTerminateCancel; + _isQuitting = [procManager terminateAllApps]; + if (_isQuitting == NO) { + NXTRunAlertPanel(_(@"Power Off"), _(@"'%@' application request to cancel Power Off."), + _(@"Dismiss"), nil, nil, [self activeApplication][@"NSApplicationName"]); } } - if (_isQuitting != NO) { + if (_isQuitting == NO) { + terminateReply = NSTerminateCancel; + } else { [self _finishTerminateProcess]; terminateReply = NSTerminateNow; ws_quit_code = WSPowerOffOnQuit; - } else { - [[NSApp mainMenu] display]; } } break; default: @@ -819,6 +808,16 @@ - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sende break; } + if (_isQuitting == NO) { + [[NSApp mainMenu] display]; + // FIXME: restore Workspace focus. It's not correct from user POV - managed application + // may want to have focus to review unsaved data. For now it's better not to have two app + // menus visible with focus mess. Currently WM info about focused window differs from + // GNUstep app. + [[NSApp mainWindow] makeKeyAndOrderFront:self]; + NSDebugLLog(@"Workspace", @"Active application: %@", [self activeApplication][@"NSApplicationName"]); + } + wDefaultScreen()->flags.ignore_focus_events = 0; return terminateReply; From 23f495265e6b21f34633191ac6ed4b3e3e3596b7 Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Tue, 10 Oct 2023 17:01:17 +0300 Subject: [PATCH 03/67] implemented -launchedApplications that called by NSWorkspace. --- Applications/Workspace/Controller+NSWorkspace.h | 7 ++++++- Applications/Workspace/Controller+NSWorkspace.m | 5 +++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Applications/Workspace/Controller+NSWorkspace.h b/Applications/Workspace/Controller+NSWorkspace.h index 49c97c4e1..929a91235 100644 --- a/Applications/Workspace/Controller+NSWorkspace.h +++ b/Applications/Workspace/Controller+NSWorkspace.h @@ -339,9 +339,14 @@ APPKIT_EXPORT NSString *NSShellCommandFileType; @"NSApplicationProcessSerialNumberLow" - The low long of the process serial number (PSN), as an NSNumber object. */ -// TODO: [NSWorkspace _workspaceApplication] +// --- [NSWorkspace _workspaceApplication] - (NSDictionary *)activeApplication; +// Return not only GNUstep application but also registered X11 applications. +// Such application record has separate field @"IsXWindowApplication" set to @"YES". +// --- [NSWorkspace _workspaceApplication] +- (NSArray*) launchedApplications; + //----------------------------------------------------------------------------- //--- Unmounting a Device //----------------------------------------------------------------------------- diff --git a/Applications/Workspace/Controller+NSWorkspace.m b/Applications/Workspace/Controller+NSWorkspace.m index ea712f82d..5abdc1743 100644 --- a/Applications/Workspace/Controller+NSWorkspace.m +++ b/Applications/Workspace/Controller+NSWorkspace.m @@ -802,6 +802,11 @@ - (NSDictionary *)activeApplication return [[ProcessManager shared] activeApplication]; } +- (NSArray *)launchedApplications +{ + return [[ProcessManager shared] applications]; +} + //------------------------------------------------------------------------------------------------- //--- Unmounting a Device //------------------------------------------------------------------------------------------------- From b0021db178e49b913d7def3aaefec5064d3a12e5 Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Wed, 11 Oct 2023 01:53:04 +0300 Subject: [PATCH 04/67] xcompmgr added as wmcomposer.c for future composer implementation use. --- Applications/Workspace/WM/wmcomposer.c | 1945 ++++++++++++++++++++++++ 1 file changed, 1945 insertions(+) create mode 100644 Applications/Workspace/WM/wmcomposer.c diff --git a/Applications/Workspace/WM/wmcomposer.c b/Applications/Workspace/WM/wmcomposer.c new file mode 100644 index 000000000..e8ac7e014 --- /dev/null +++ b/Applications/Workspace/WM/wmcomposer.c @@ -0,0 +1,1945 @@ +/* + * Copyright © 2003 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* Modified by Matthew Hawn. I don't know what to say here so follow what it + says above. Not that I can really do anything about it +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct _ignore { + struct _ignore *next; + unsigned long sequence; +} ignore; + +typedef struct _win { + struct _win *next; + Window id; + Pixmap pixmap; + XWindowAttributes a; + int mode; + int damaged; + Damage damage; + Picture picture; + Picture alphaPict; + Picture shadowPict; + XserverRegion borderSize; + XserverRegion extents; + Picture shadow; + int shadow_dx; + int shadow_dy; + int shadow_width; + int shadow_height; + unsigned int opacity; + Atom windowType; + unsigned long damage_sequence; /* sequence when damage was created */ + Bool shaped; + XRectangle shape_bounds; + + /* for drawing translucent windows */ + XserverRegion borderClip; + struct _win *prev_trans; +} win; + +typedef struct _conv { + int size; + double *data; +} conv; + +typedef struct _fade { + struct _fade *next; + win *w; + double cur; + double finish; + double step; + void (*callback)(Display *dpy, win *w, Bool gone); + Display *dpy; + Bool gone; +} fade; + +static win *list; +static fade *fades; +static int scr; +static Window root; +static Picture rootPicture; +static Picture rootBuffer; +static Picture blackPicture; +static Picture transBlackPicture; +static Picture rootTile; +static XserverRegion allDamage; +static Bool clipChanged; +static Bool hasNamePixmap; +static int root_height, root_width; +static ignore *ignore_head, **ignore_tail = &ignore_head; +static int xfixes_event, xfixes_error; +static int damage_event, damage_error; +static int composite_event, composite_error; +static int render_event, render_error; +static int xshape_event, xshape_error; +static Bool synchronize; +static int composite_opcode; + +/* find these once and be done with it */ +static Atom opacityAtom; +static Atom winTypeAtom; +static Atom winDesktopAtom; +static Atom winDockAtom; +static Atom winToolbarAtom; +static Atom winMenuAtom; +static Atom winUtilAtom; +static Atom winSplashAtom; +static Atom winDialogAtom; +static Atom winNormalAtom; + +/* opacity property name; sometime soon I'll write up an EWMH spec for it */ +#define OPACITY_PROP "_NET_WM_WINDOW_OPACITY" + +#define TRANSLUCENT 0xe0000000 +#define OPAQUE 0xffffffff + +static conv *gaussianMap; + +#define WINDOW_SOLID 0 +#define WINDOW_TRANS 1 +#define WINDOW_ARGB 2 + +typedef enum _compMode { + CompSimple, /* looks like a regular X server */ + CompServerShadows, /* use window alpha for shadow; sharp, but precise */ + CompClientShadows, /* use window extents for shadow, blurred */ +} CompMode; + +static void determine_mode(Display *dpy, win *w); + +static double get_opacity_percent(Display *dpy, win *w, double def); + +static unsigned int get_opacity_prop(Display *dpy, win *w, unsigned int def); + +static XserverRegion win_extents(Display *dpy, win *w); + +static CompMode compMode = CompSimple; + +static int shadowRadius = 12; +static int shadowOffsetX = -15; +static int shadowOffsetY = -15; +static double shadowOpacity = .75; + +static double fade_in_step = 0.028; +static double fade_out_step = 0.03; +static int fade_delta = 10; +static int fade_time = 0; +static Bool fadeWindows = False; +static Bool excludeDockShadows = False; +static Bool fadeTrans = False; + +static Bool autoRedirect = False; + +/* For shadow precomputation */ +static int Gsize = -1; +static unsigned char *shadowCorner = NULL; +static unsigned char *shadowTop = NULL; + +static int get_time_in_milliseconds(void) +{ + struct timeval tv; + + gettimeofday(&tv, NULL); + return tv.tv_sec * 1000 + tv.tv_usec / 1000; +} + +// ---------------------------------------------------------------------------------------------- +// Fading +// ---------------------------------------------------------------------------------------------- + +static fade *find_fade(win *w) +{ + fade *f; + + for (f = fades; f; f = f->next) { + if (f->w == w) { + return f; + } + } + return NULL; +} + +static void dequeue_fade(Display *dpy, fade *f) +{ + fade **prev; + + for (prev = &fades; *prev; prev = &(*prev)->next) + if (*prev == f) { + *prev = f->next; + if (f->callback) { + (*f->callback)(dpy, f->w, f->gone); + } + free(f); + break; + } +} + +static void cleanup_fade(Display *dpy, win *w) +{ + fade *f = find_fade(w); + if (f) { + dequeue_fade(dpy, f); + } +} + +static void enqueue_fade(Display *dpy, fade *f) +{ + if (!fades) { + fade_time = get_time_in_milliseconds() + fade_delta; + } + f->next = fades; + fades = f; +} + +static void set_fade(Display *dpy, win *w, double start, double finish, double step, + void (*callback)(Display *dpy, win *w, Bool gone), Bool gone, + Bool exec_callback, Bool override) +{ + fade *f; + + f = find_fade(w); + if (!f) { + f = malloc(sizeof(fade)); + f->next = NULL; + f->w = w; + f->cur = start; + enqueue_fade(dpy, f); + } else if (!override) { + return; + } else { + if (exec_callback) { + if (f->callback) { + (*f->callback)(dpy, f->w, f->gone); + } + } + } + + if (finish < 0) { + finish = 0; + } + if (finish > 1) { + finish = 1; + } + f->finish = finish; + if (f->cur < finish) { + f->step = step; + } else if (f->cur > finish) { + f->step = -step; + } + f->callback = callback; + f->gone = gone; + w->opacity = f->cur * OPAQUE; + determine_mode(dpy, w); + if (w->shadow) { + XRenderFreePicture(dpy, w->shadow); + w->shadow = None; + w->extents = win_extents(dpy, w); + } +} + +static int fade_timeout(void) +{ + int now; + int delta; + if (!fades) { + return -1; + } + now = get_time_in_milliseconds(); + delta = fade_time - now; + if (delta < 0) { + delta = 0; + } + return delta; +} + +static void run_fades(Display *dpy) +{ + int now = get_time_in_milliseconds(); + fade *next = fades; + int steps; + Bool need_dequeue; + + if (fade_time - now > 0) + return; + steps = 1 + (now - fade_time) / fade_delta; + + while (next) { + fade *f = next; + win *w = f->w; + next = f->next; + f->cur += f->step * steps; + if (f->cur >= 1) { + f->cur = 1; + } else if (f->cur < 0) { + f->cur = 0; + } + w->opacity = f->cur * OPAQUE; + need_dequeue = False; + if (f->step > 0) { + if (f->cur >= f->finish) { + w->opacity = f->finish * OPAQUE; + need_dequeue = True; + } + } else { + if (f->cur <= f->finish) { + w->opacity = f->finish * OPAQUE; + need_dequeue = True; + } + } + determine_mode(dpy, w); + if (w->shadow) { + XRenderFreePicture(dpy, w->shadow); + w->shadow = None; + w->extents = win_extents(dpy, w); + } + /* Must do this last as it might destroy f->w in callbacks */ + if (need_dequeue) { + dequeue_fade(dpy, f); + } + } + fade_time = now + fade_delta; +} + +// ---------------------------------------------------------------------------------------------- +// Gaussian +// ---------------------------------------------------------------------------------------------- +static double gaussian(double r, double x, double y) +{ + return ((1 / (sqrt(2 * M_PI * r))) * exp((-(x * x + y * y)) / (2 * r * r))); +} + +static conv *make_gaussian_map(Display *dpy, double r) +{ + conv *c; + int size = ((int)ceil((r * 3)) + 1) & ~1; + int center = size / 2; + int x, y; + double t; + double g; + + c = malloc(sizeof(conv) + size * size * sizeof(double)); + c->size = size; + c->data = (double *)(c + 1); + t = 0.0; + for (y = 0; y < size; y++) + for (x = 0; x < size; x++) { + g = gaussian(r, (double)(x - center), (double)(y - center)); + t += g; + c->data[y * size + x] = g; + } + for (y = 0; y < size; y++) { + for (x = 0; x < size; x++) { + c->data[y * size + x] /= t; + } + } + return c; +} + +/* + * A picture will help + * + * -center 0 width width+center + * -center +-----+-------------------+-----+ + * | | | | + * | | | | + * 0 +-----+-------------------+-----+ + * | | | | + * | | | | + * | | | | + * height +-----+-------------------+-----+ + * | | | | + * height+ | | | | + * center +-----+-------------------+-----+ + */ + +static unsigned char sum_gaussian(conv *map, double opacity, int x, int y, int width, int height) +{ + int fx, fy; + double *g_line = map->data; + int g_size = map->size; + int center = g_size / 2; + int fx_start, fx_end; + int fy_start, fy_end; + double v; + + /* + * Compute set of filter values which are "in range", + * that's the set with: + * 0 <= x + (fx-center) && x + (fx-center) < width && + * 0 <= y + (fy-center) && y + (fy-center) < height + * + * 0 <= x + (fx - center) x + fx - center < width + * center - x <= fx fx < width + center - x + */ + + fx_start = center - x; + if (fx_start < 0) { + fx_start = 0; + } + fx_end = width + center - x; + if (fx_end > g_size) { + fx_end = g_size; + } + + fy_start = center - y; + if (fy_start < 0) { + fy_start = 0; + } + fy_end = height + center - y; + if (fy_end > g_size) { + fy_end = g_size; + } + + g_line = g_line + fy_start * g_size + fx_start; + + v = 0; + for (fy = fy_start; fy < fy_end; fy++) { + double *g_data = g_line; + g_line += g_size; + + for (fx = fx_start; fx < fx_end; fx++) { + v += *g_data++; + } + } + if (v > 1) { + v = 1; + } + + return ((unsigned char)(v * opacity * 255.0)); +} + +/* precompute shadow corners and sides to save time for large windows */ +static void presum_gaussian(conv *map) +{ + int center = map->size / 2; + int opacity, x, y; + + Gsize = map->size; + + if (shadowCorner) { + free(shadowCorner); + } + if (shadowTop) { + free(shadowTop); + } + + shadowCorner = malloc((Gsize + 1) * (Gsize + 1) * 26); + shadowTop = malloc((Gsize + 1) * 26); + + for (x = 0; x <= Gsize; x++) { + shadowTop[25 * (Gsize + 1) + x] = + sum_gaussian(map, 1, x - center, center, Gsize * 2, Gsize * 2); + for (opacity = 0; opacity < 25; opacity++) { + shadowTop[opacity * (Gsize + 1) + x] = shadowTop[25 * (Gsize + 1) + x] * opacity / 25; + } + for (y = 0; y <= x; y++) { + shadowCorner[25 * (Gsize + 1) * (Gsize + 1) + y * (Gsize + 1) + x] = + sum_gaussian(map, 1, x - center, y - center, Gsize * 2, Gsize * 2); + shadowCorner[25 * (Gsize + 1) * (Gsize + 1) + x * (Gsize + 1) + y] = + shadowCorner[25 * (Gsize + 1) * (Gsize + 1) + y * (Gsize + 1) + x]; + for (opacity = 0; opacity < 25; opacity++) { + shadowCorner[opacity * (Gsize + 1) * (Gsize + 1) + y * (Gsize + 1) + x] = + shadowCorner[opacity * (Gsize + 1) * (Gsize + 1) + x * (Gsize + 1) + y] = + shadowCorner[25 * (Gsize + 1) * (Gsize + 1) + y * (Gsize + 1) + x] * opacity / 25; + } + } + } +} + +// ---------------------------------------------------------------------------------------------- +// Shadows +// ---------------------------------------------------------------------------------------------- +static XImage *make_shadow(Display *dpy, double opacity, int width, int height) +{ + XImage *ximage; + unsigned char *data; + int gsize = gaussianMap->size; + int ylimit, xlimit; + int swidth = width + gsize; + int sheight = height + gsize; + int center = gsize / 2; + int x, y; + unsigned char d; + int x_diff; + int opacity_int = (int)(opacity * 25); + data = malloc(swidth * sheight * sizeof(unsigned char)); + if (!data) + return NULL; + ximage = XCreateImage(dpy, DefaultVisual(dpy, DefaultScreen(dpy)), 8, ZPixmap, 0, (char *)data, + swidth, sheight, 8, swidth * sizeof(unsigned char)); + if (!ximage) { + free(data); + return NULL; + } + /* + * Build the gaussian in sections + */ + + /* + * center (fill the complete data array) + */ + if (Gsize > 0) + d = shadowTop[opacity_int * (Gsize + 1) + Gsize]; + else + d = sum_gaussian(gaussianMap, opacity, center, center, width, height); + memset(data, d, sheight * swidth); + + /* + * corners + */ + ylimit = gsize; + if (ylimit > sheight / 2) { + ylimit = (sheight + 1) / 2; + } + xlimit = gsize; + if (xlimit > swidth / 2) { + xlimit = (swidth + 1) / 2; + } + + for (y = 0; y < ylimit; y++) { + for (x = 0; x < xlimit; x++) { + if (xlimit == Gsize && ylimit == Gsize) { + d = shadowCorner[opacity_int * (Gsize + 1) * (Gsize + 1) + y * (Gsize + 1) + x]; + } else { + d = sum_gaussian(gaussianMap, opacity, x - center, y - center, width, height); + } + data[y * swidth + x] = d; + data[(sheight - y - 1) * swidth + x] = d; + data[(sheight - y - 1) * swidth + (swidth - x - 1)] = d; + data[y * swidth + (swidth - x - 1)] = d; + } + } + /* + * top/bottom + */ + x_diff = swidth - (gsize * 2); + if (x_diff > 0 && ylimit > 0) { + for (y = 0; y < ylimit; y++) { + if (ylimit == Gsize) { + d = shadowTop[opacity_int * (Gsize + 1) + y]; + } else { + d = sum_gaussian(gaussianMap, opacity, center, y - center, width, height); + } + memset(&data[y * swidth + gsize], d, x_diff); + memset(&data[(sheight - y - 1) * swidth + gsize], d, x_diff); + } + } + + /* + * sides + */ + + for (x = 0; x < xlimit; x++) { + if (xlimit == Gsize) { + d = shadowTop[opacity_int * (Gsize + 1) + x]; + } else { + d = sum_gaussian(gaussianMap, opacity, x - center, center, width, height); + } + for (y = gsize; y < sheight - gsize; y++) { + data[y * swidth + x] = d; + data[y * swidth + (swidth - x - 1)] = d; + } + } + + return ximage; +} + +static Picture shadow_picture(Display *dpy, double opacity, Picture alpha_pict, int width, + int height, int *wp, int *hp) +{ + XImage *shadowImage; + Pixmap shadowPixmap; + Picture shadowPicture; + GC gc; + + shadowImage = make_shadow(dpy, opacity, width, height); + if (!shadowImage) { + return None; + } + shadowPixmap = XCreatePixmap(dpy, root, shadowImage->width, shadowImage->height, 8); + if (!shadowPixmap) { + XDestroyImage(shadowImage); + return None; + } + + shadowPicture = XRenderCreatePicture(dpy, shadowPixmap, + XRenderFindStandardFormat(dpy, PictStandardA8), 0, NULL); + if (!shadowPicture) { + XDestroyImage(shadowImage); + XFreePixmap(dpy, shadowPixmap); + return (Picture)None; + } + + gc = XCreateGC(dpy, shadowPixmap, 0, NULL); + if (!gc) { + XDestroyImage(shadowImage); + XFreePixmap(dpy, shadowPixmap); + XRenderFreePicture(dpy, shadowPicture); + return (Picture)None; + } + + XPutImage(dpy, shadowPixmap, gc, shadowImage, 0, 0, 0, 0, shadowImage->width, + shadowImage->height); + *wp = shadowImage->width; + *hp = shadowImage->height; + XFreeGC(dpy, gc); + XDestroyImage(shadowImage); + XFreePixmap(dpy, shadowPixmap); + return shadowPicture; +} + + +static Picture solid_picture(Display *dpy, Bool argb, double a, double r, double g, double b) +{ + Pixmap pixmap; + Picture picture; + XRenderPictureAttributes pa; + XRenderColor c; + + pixmap = XCreatePixmap(dpy, root, 1, 1, argb ? 32 : 8); + if (!pixmap) { + return None; + } + + pa.repeat = True; + picture = XRenderCreatePicture( + dpy, pixmap, XRenderFindStandardFormat(dpy, argb ? PictStandardARGB32 : PictStandardA8), + CPRepeat, &pa); + if (!picture) { + XFreePixmap(dpy, pixmap); + return None; + } + + c.alpha = a * 0xffff; + c.red = r * 0xffff; + c.green = g * 0xffff; + c.blue = b * 0xffff; + XRenderFillRectangle(dpy, PictOpSrc, picture, &c, 0, 0, 1, 1); + XFreePixmap(dpy, pixmap); + return picture; +} + +static void discard_ignore(Display *dpy, unsigned long sequence) +{ + while (ignore_head) { + if ((long)(sequence - ignore_head->sequence) > 0) { + ignore *next = ignore_head->next; + free(ignore_head); + ignore_head = next; + if (!ignore_head) { + ignore_tail = &ignore_head; + } + } else { + break; + } + } +} + +static void set_ignore(Display *dpy, unsigned long sequence) +{ + ignore *i = malloc(sizeof(ignore)); + + if (!i) { + return; + } + + i->sequence = sequence; + i->next = NULL; + *ignore_tail = i; + ignore_tail = &i->next; +} + +static int should_ignore(Display *dpy, unsigned long sequence) +{ + discard_ignore(dpy, sequence); + return ignore_head && ignore_head->sequence == sequence; +} + +static win *find_win(Display *dpy, Window id) +{ + win *w; + + for (w = list; w; w = w->next) { + if (w->id == id) { + return w; + } + } + return NULL; +} + +static const char *backgroundProps[] = { + "_XROOTPMAP_ID", + "_XSETROOT_ID", + NULL, +}; + +static Picture root_tile(Display *dpy) +{ + Picture picture; + Atom actual_type; + Pixmap pixmap; + int actual_format; + unsigned long nitems; + unsigned long bytes_after; + unsigned char *prop; + Bool fill; + XRenderPictureAttributes pa; + int p; + + pixmap = None; + for (p = 0; backgroundProps[p]; p++) { + if (XGetWindowProperty(dpy, root, XInternAtom(dpy, backgroundProps[p], False), 0, 4, False, + AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes_after, + &prop) == Success && + actual_type == XInternAtom(dpy, "PIXMAP", False) && actual_format == 32 && nitems == 1) { + memcpy(&pixmap, prop, 4); + XFree(prop); + fill = False; + break; + } + } + if (!pixmap) { + pixmap = XCreatePixmap(dpy, root, 1, 1, DefaultDepth(dpy, scr)); + fill = True; + } + pa.repeat = True; + picture = XRenderCreatePicture(dpy, pixmap, XRenderFindVisualFormat(dpy, DefaultVisual(dpy, scr)), + CPRepeat, &pa); + if (fill) { + XRenderColor c; + + c.red = c.green = c.blue = 0x8080; + c.alpha = 0xffff; + XRenderFillRectangle(dpy, PictOpSrc, picture, &c, 0, 0, 1, 1); + } + return picture; +} + +static void paint_root(Display *dpy) +{ + if (!rootTile) { + rootTile = root_tile(dpy); + } + + XRenderComposite(dpy, PictOpSrc, rootTile, None, rootBuffer, 0, 0, 0, 0, 0, 0, root_width, + root_height); +} + +static XserverRegion win_extents(Display *dpy, win *w) +{ + XRectangle r; + + r.x = w->a.x; + r.y = w->a.y; + r.width = w->a.width + w->a.border_width * 2; + r.height = w->a.height + w->a.border_width * 2; + if (compMode != CompSimple && !(w->windowType == winDockAtom && excludeDockShadows)) { + if (compMode == CompServerShadows || w->mode != WINDOW_ARGB) { + XRectangle sr; + + if (compMode == CompServerShadows) { + w->shadow_dx = 2; + w->shadow_dy = 7; + w->shadow_width = w->a.width; + w->shadow_height = w->a.height; + } else { + w->shadow_dx = shadowOffsetX; + w->shadow_dy = shadowOffsetY; + if (!w->shadow) { + double opacity = shadowOpacity; + if (w->mode == WINDOW_TRANS) { + opacity = opacity * ((double)w->opacity) / ((double)OPAQUE); + } + w->shadow = shadow_picture(dpy, opacity, w->alphaPict, w->a.width + w->a.border_width * 2, + w->a.height + w->a.border_width * 2, &w->shadow_width, + &w->shadow_height); + } + } + sr.x = w->a.x + w->shadow_dx; + sr.y = w->a.y + w->shadow_dy; + sr.width = w->shadow_width; + sr.height = w->shadow_height; + if (sr.x < r.x) { + r.width = (r.x + r.width) - sr.x; + r.x = sr.x; + } + if (sr.y < r.y) { + r.height = (r.y + r.height) - sr.y; + r.y = sr.y; + } + if (sr.x + sr.width > r.x + r.width) { + r.width = sr.x + sr.width - r.x; + } + if (sr.y + sr.height > r.y + r.height) { + r.height = sr.y + sr.height - r.y; + } + } + } + return XFixesCreateRegion(dpy, &r, 1); +} + +static XserverRegion border_size(Display *dpy, win *w) +{ + XserverRegion border; + /* + * if window doesn't exist anymore, this will generate an error + * as well as not generate a region. Perhaps a better XFixes + * architecture would be to have a request that copies instead + * of creates, that way you'd just end up with an empty region + * instead of an invalid XID. + */ + set_ignore(dpy, NextRequest(dpy)); + border = XFixesCreateRegionFromWindow(dpy, w->id, WindowRegionBounding); + /* translate this */ + set_ignore(dpy, NextRequest(dpy)); + XFixesTranslateRegion(dpy, border, w->a.x + w->a.border_width, w->a.y + w->a.border_width); + return border; +} + +static void paint_all(Display *dpy, XserverRegion region) +{ + win *w; + win *t = NULL; + + if (!region) { + XRectangle r; + r.x = 0; + r.y = 0; + r.width = root_width; + r.height = root_height; + region = XFixesCreateRegion(dpy, &r, 1); + } + if (!rootBuffer) { + Pixmap rootPixmap = XCreatePixmap(dpy, root, root_width, root_height, DefaultDepth(dpy, scr)); + rootBuffer = XRenderCreatePicture( + dpy, rootPixmap, XRenderFindVisualFormat(dpy, DefaultVisual(dpy, scr)), 0, NULL); + XFreePixmap(dpy, rootPixmap); + } + XFixesSetPictureClipRegion(dpy, rootPicture, 0, 0, region); + for (w = list; w; w = w->next) { + /* never painted, ignore it */ + if (!w->damaged) { + continue; + } + /* if invisible, ignore it */ + if (w->a.x + w->a.width < 1 || w->a.y + w->a.height < 1 || w->a.x >= root_width || + w->a.y >= root_height) { + continue; + } + if (!w->picture) { + XRenderPictureAttributes pa; + XRenderPictFormat *format; + Drawable draw = w->id; + + if (hasNamePixmap && !w->pixmap) { + w->pixmap = XCompositeNameWindowPixmap(dpy, w->id); + } + if (w->pixmap) { + draw = w->pixmap; + } + format = XRenderFindVisualFormat(dpy, w->a.visual); + pa.subwindow_mode = IncludeInferiors; + w->picture = XRenderCreatePicture(dpy, draw, format, CPSubwindowMode, &pa); + } + if (clipChanged) { + if (w->borderSize) { + set_ignore(dpy, NextRequest(dpy)); + XFixesDestroyRegion(dpy, w->borderSize); + w->borderSize = None; + } + if (w->extents) { + XFixesDestroyRegion(dpy, w->extents); + w->extents = None; + } + if (w->borderClip) { + XFixesDestroyRegion(dpy, w->borderClip); + w->borderClip = None; + } + } + if (!w->borderSize) { + w->borderSize = border_size(dpy, w); + } + if (!w->extents) { + w->extents = win_extents(dpy, w); + } + if (w->mode == WINDOW_SOLID) { + int x, y, wid, hei; + x = w->a.x; + y = w->a.y; + wid = w->a.width + w->a.border_width * 2; + hei = w->a.height + w->a.border_width * 2; + XFixesSetPictureClipRegion(dpy, rootBuffer, 0, 0, region); + set_ignore(dpy, NextRequest(dpy)); + XFixesSubtractRegion(dpy, region, region, w->borderSize); + set_ignore(dpy, NextRequest(dpy)); + XRenderComposite(dpy, PictOpSrc, w->picture, None, rootBuffer, 0, 0, 0, 0, x, y, wid, hei); + } + if (!w->borderClip) { + w->borderClip = XFixesCreateRegion(dpy, NULL, 0); + XFixesCopyRegion(dpy, w->borderClip, region); + } + w->prev_trans = t; + t = w; + } + XFixesSetPictureClipRegion(dpy, rootBuffer, 0, 0, region); + paint_root(dpy); + for (w = t; w; w = w->prev_trans) { + XFixesSetPictureClipRegion(dpy, rootBuffer, 0, 0, w->borderClip); + switch (compMode) { + case CompSimple: + break; + case CompServerShadows: + /* dont' bother drawing shadows on desktop windows */ + if (w->windowType == winDesktopAtom) + break; + set_ignore(dpy, NextRequest(dpy)); + if (w->opacity != OPAQUE && !w->shadowPict) + w->shadowPict = solid_picture(dpy, True, (double)w->opacity / OPAQUE * 0.3, 0, 0, 0); + XRenderComposite(dpy, PictOpOver, w->shadowPict ? w->shadowPict : transBlackPicture, + w->picture, rootBuffer, 0, 0, 0, 0, w->a.x + w->shadow_dx, + w->a.y + w->shadow_dy, w->shadow_width, w->shadow_height); + break; + case CompClientShadows: + /* don't bother drawing shadows on desktop windows */ + if (w->shadow && w->windowType != winDesktopAtom) { + XRenderComposite(dpy, PictOpOver, blackPicture, w->shadow, rootBuffer, 0, 0, 0, 0, + w->a.x + w->shadow_dx, w->a.y + w->shadow_dy, w->shadow_width, + w->shadow_height); + } + break; + } + if (w->opacity != OPAQUE && !w->alphaPict) { + w->alphaPict = solid_picture(dpy, False, (double)w->opacity / OPAQUE, 0, 0, 0); + } + if (w->mode == WINDOW_TRANS) { + int x, y, wid, hei; + XFixesIntersectRegion(dpy, w->borderClip, w->borderClip, w->borderSize); + XFixesSetPictureClipRegion(dpy, rootBuffer, 0, 0, w->borderClip); + x = w->a.x; + y = w->a.y; + wid = w->a.width + w->a.border_width * 2; + hei = w->a.height + w->a.border_width * 2; + set_ignore(dpy, NextRequest(dpy)); + XRenderComposite(dpy, PictOpOver, w->picture, w->alphaPict, rootBuffer, 0, 0, 0, 0, x, y, wid, + hei); + } else if (w->mode == WINDOW_ARGB) { + int x, y, wid, hei; + XFixesIntersectRegion(dpy, w->borderClip, w->borderClip, w->borderSize); + XFixesSetPictureClipRegion(dpy, rootBuffer, 0, 0, w->borderClip); + x = w->a.x; + y = w->a.y; + wid = w->a.width + w->a.border_width * 2; + hei = w->a.height + w->a.border_width * 2; + set_ignore(dpy, NextRequest(dpy)); + XRenderComposite(dpy, PictOpOver, w->picture, w->alphaPict, rootBuffer, 0, 0, 0, 0, x, y, wid, + hei); + } + XFixesDestroyRegion(dpy, w->borderClip); + w->borderClip = None; + } + XFixesDestroyRegion(dpy, region); + if (rootBuffer != rootPicture) { + XFixesSetPictureClipRegion(dpy, rootBuffer, 0, 0, None); + XRenderComposite(dpy, PictOpSrc, rootBuffer, None, rootPicture, 0, 0, 0, 0, 0, 0, root_width, + root_height); + } +} + +static void add_damage(Display *dpy, XserverRegion damage) +{ + if (allDamage) { + XFixesUnionRegion(dpy, allDamage, allDamage, damage); + XFixesDestroyRegion(dpy, damage); + } else { + allDamage = damage; + } +} + +static void repair_win(Display *dpy, win *w) +{ + XserverRegion parts; + + if (!w->damaged) { + parts = win_extents(dpy, w); + set_ignore(dpy, NextRequest(dpy)); + XDamageSubtract(dpy, w->damage, None, None); + } else { + parts = XFixesCreateRegion(dpy, NULL, 0); + set_ignore(dpy, NextRequest(dpy)); + XDamageSubtract(dpy, w->damage, None, parts); + XFixesTranslateRegion(dpy, parts, w->a.x + w->a.border_width, w->a.y + w->a.border_width); + if (compMode == CompServerShadows) { + XserverRegion o = XFixesCreateRegion(dpy, NULL, 0); + XFixesCopyRegion(dpy, o, parts); + XFixesTranslateRegion(dpy, o, w->shadow_dx, w->shadow_dy); + XFixesUnionRegion(dpy, parts, parts, o); + XFixesDestroyRegion(dpy, o); + } + } + add_damage(dpy, parts); + w->damaged = 1; +} + +static void map_win(Display *dpy, Window id, unsigned long sequence, Bool doFade) +{ + win *w = find_win(dpy, id); + + if (!w) { + return; + } + w->a.map_state = IsViewable; + + /* This needs to be here or else we lose transparency messages */ + XSelectInput(dpy, id, PropertyChangeMask); + + /* This needs to be here since we don't get PropertyNotify when unmapped */ + w->opacity = get_opacity_prop(dpy, w, OPAQUE); + determine_mode(dpy, w); + + w->damaged = 0; + + if (doFade && fadeWindows) { + set_fade(dpy, w, 0, get_opacity_percent(dpy, w, 1.0), fade_in_step, NULL, False, True, True); + } +} + +static void finish_unmap_win(Display *dpy, win *w) +{ + w->damaged = 0; + if (w->extents != None) { + add_damage(dpy, w->extents); /* destroys region */ + w->extents = None; + } + + if (w->pixmap) { + XFreePixmap(dpy, w->pixmap); + w->pixmap = None; + } + + if (w->picture) { + set_ignore(dpy, NextRequest(dpy)); + XRenderFreePicture(dpy, w->picture); + w->picture = None; + } + + /* don't care about properties anymore */ + set_ignore(dpy, NextRequest(dpy)); + XSelectInput(dpy, w->id, 0); + + if (w->borderSize) { + set_ignore(dpy, NextRequest(dpy)); + XFixesDestroyRegion(dpy, w->borderSize); + w->borderSize = None; + } + if (w->shadow) { + XRenderFreePicture(dpy, w->shadow); + w->shadow = None; + } + if (w->borderClip) { + XFixesDestroyRegion(dpy, w->borderClip); + w->borderClip = None; + } + + clipChanged = True; +} + +static void unmap_callback(Display *dpy, win *w, Bool gone) { finish_unmap_win(dpy, w); } + +static void unmap_win(Display *dpy, Window id, Bool doFade) +{ + win *w = find_win(dpy, id); + if (!w) { + return; + } + w->a.map_state = IsUnmapped; + if (w->pixmap && doFade && fadeWindows) { + set_fade(dpy, w, w->opacity * 1.0 / OPAQUE, 0.0, fade_out_step, unmap_callback, False, False, + True); + } else { + finish_unmap_win(dpy, w); + } +} + +/* Get the opacity prop from window + not found: default + otherwise the value + */ +static unsigned int get_opacity_prop(Display *dpy, win *w, unsigned int def) +{ + Atom actual; + int format; + unsigned long n, left; + + unsigned char *data; + int result = XGetWindowProperty(dpy, w->id, opacityAtom, 0L, 1L, False, XA_CARDINAL, &actual, + &format, &n, &left, &data); + if (result == Success && data != NULL) { + unsigned int i; + memcpy(&i, data, sizeof(unsigned int)); + XFree((void *)data); + return i; + } + return def; +} + +/* Get the opacity property from the window in a percent format + not found: default + otherwise: the value +*/ +static double get_opacity_percent(Display *dpy, win *w, double def) +{ + unsigned int opacity = get_opacity_prop(dpy, w, (unsigned int)(OPAQUE * def)); + + return opacity * 1.0 / OPAQUE; +} + +/* determine mode for window all in one place. + Future might check for menu flag and other cool things +*/ + +static Atom get_wintype_prop(Display *dpy, Window w) +{ + Atom actual; + int format; + unsigned long n, left; + + unsigned char *data; + int result = XGetWindowProperty(dpy, w, winTypeAtom, 0L, 1L, False, XA_ATOM, &actual, &format, &n, + &left, &data); + + if (result == Success && data != (unsigned char *)None) { + Atom a; + memcpy(&a, data, sizeof(Atom)); + XFree((void *)data); + return a; + } + return winNormalAtom; +} + +static void determine_mode(Display *dpy, win *w) +{ + int mode; + XRenderPictFormat *format; + + /* if trans prop == -1 fall back on previous tests*/ + + if (w->alphaPict) { + XRenderFreePicture(dpy, w->alphaPict); + w->alphaPict = None; + } + if (w->shadowPict) { + XRenderFreePicture(dpy, w->shadowPict); + w->shadowPict = None; + } + + if (w->a.class == InputOnly) { + format = NULL; + } else { + format = XRenderFindVisualFormat(dpy, w->a.visual); + } + + if (format && format->type == PictTypeDirect && format->direct.alphaMask) { + mode = WINDOW_ARGB; + } else if (w->opacity != OPAQUE) { + mode = WINDOW_TRANS; + } else { + mode = WINDOW_SOLID; + } + w->mode = mode; + if (w->extents) { + XserverRegion damage; + damage = XFixesCreateRegion(dpy, NULL, 0); + XFixesCopyRegion(dpy, damage, w->extents); + add_damage(dpy, damage); + } +} + +static Atom determine_wintype(Display *dpy, Window w) +{ + Window root_return, parent_return; + Window *children = NULL; + unsigned int nchildren; + Atom type; + + type = get_wintype_prop(dpy, w); + if (type != winNormalAtom) + return type; + + if (!XQueryTree(dpy, w, &root_return, &parent_return, &children, &nchildren)) { + /* XQueryTree failed. */ + if (children) { + XFree((void *)children); + } + return winNormalAtom; + } + + for (unsigned int i = 0; i < nchildren; i++) { + type = determine_wintype(dpy, children[i]); + if (type != winNormalAtom) { + return type; + } + } + + if (children) + XFree((void *)children); + + return winNormalAtom; +} + +static void add_win(Display *dpy, Window id, Window prev) +{ + win *new = malloc(sizeof(win)); + win **p; + + if (!new) + return; + if (prev) { + for (p = &list; *p; p = &(*p)->next) { + if ((*p)->id == prev) { + break; + } + } + } else { + p = &list; + } + new->id = id; + set_ignore(dpy, NextRequest(dpy)); + if (!XGetWindowAttributes(dpy, id, &new->a)) { + free(new); + return; + } + new->shaped = False; + new->shape_bounds.x = new->a.x; + new->shape_bounds.y = new->a.y; + new->shape_bounds.width = new->a.width; + new->shape_bounds.height = new->a.height; + new->damaged = 0; + new->pixmap = None; + new->picture = None; + if (new->a.class == InputOnly) { + new->damage_sequence = 0; + new->damage = None; + } else { + new->damage_sequence = NextRequest(dpy); + new->damage = XDamageCreate(dpy, id, XDamageReportNonEmpty); + XShapeSelectInput(dpy, id, ShapeNotifyMask); + } + new->alphaPict = None; + new->shadowPict = None; + new->borderSize = None; + new->extents = None; + new->shadow = None; + new->shadow_dx = 0; + new->shadow_dy = 0; + new->shadow_width = 0; + new->shadow_height = 0; + new->opacity = OPAQUE; + + new->borderClip = None; + new->prev_trans = NULL; + + new->windowType = determine_wintype(dpy, new->id); + + new->next = *p; + *p = new; + if (new->a.map_state == IsViewable) { + map_win(dpy, id, new->damage_sequence - 1, True); + } +} + +static void restack_win(Display *dpy, win *w, Window new_above) +{ + Window old_above; + + if (w->next) { + old_above = w->next->id; + } else { + old_above = None; + } + if (old_above != new_above) { + win **prev; + + /* unhook */ + for (prev = &list; *prev; prev = &(*prev)->next) { + if ((*prev) == w) { + break; + } + } + *prev = w->next; + + /* rehook */ + for (prev = &list; *prev; prev = &(*prev)->next) { + if ((*prev)->id == new_above) { + break; + } + } + w->next = *prev; + *prev = w; + } +} + +static void configure_win(Display *dpy, XConfigureEvent *ce) +{ + win *w = find_win(dpy, ce->window); + XserverRegion damage = None; + + if (!w) { + if (ce->window == root) { + if (rootBuffer) { + XRenderFreePicture(dpy, rootBuffer); + rootBuffer = None; + } + root_width = ce->width; + root_height = ce->height; + } + return; + } + damage = XFixesCreateRegion(dpy, NULL, 0); + if (w->extents != None) { + XFixesCopyRegion(dpy, damage, w->extents); + } + w->shape_bounds.x -= w->a.x; + w->shape_bounds.y -= w->a.y; + w->a.x = ce->x; + w->a.y = ce->y; + if (w->a.width != ce->width || w->a.height != ce->height) { + if (w->pixmap) { + XFreePixmap(dpy, w->pixmap); + w->pixmap = None; + if (w->picture) { + XRenderFreePicture(dpy, w->picture); + w->picture = None; + } + } + if (w->shadow) { + XRenderFreePicture(dpy, w->shadow); + w->shadow = None; + } + } + w->a.width = ce->width; + w->a.height = ce->height; + w->a.border_width = ce->border_width; + w->a.override_redirect = ce->override_redirect; + restack_win(dpy, w, ce->above); + if (damage) { + XserverRegion extents = win_extents(dpy, w); + XFixesUnionRegion(dpy, damage, damage, extents); + XFixesDestroyRegion(dpy, extents); + add_damage(dpy, damage); + } + w->shape_bounds.x += w->a.x; + w->shape_bounds.y += w->a.y; + if (!w->shaped) { + w->shape_bounds.width = w->a.width; + w->shape_bounds.height = w->a.height; + } + + clipChanged = True; +} + +static void circulate_win(Display *dpy, XCirculateEvent *ce) +{ + win *w = find_win(dpy, ce->window); + Window new_above; + + if (!w) { + return; + } + if (ce->place == PlaceOnTop) { + new_above = list->id; + } else { + new_above = None; + } + restack_win(dpy, w, new_above); + clipChanged = True; +} + +static void finish_destroy_win(Display *dpy, Window id, Bool gone) +{ + win **prev, *w; + + for (prev = &list; (w = *prev); prev = &w->next) { + if (w->id == id) { + if (gone) { + finish_unmap_win(dpy, w); + } + *prev = w->next; + if (w->picture) { + set_ignore(dpy, NextRequest(dpy)); + XRenderFreePicture(dpy, w->picture); + w->picture = None; + } + if (w->alphaPict) { + XRenderFreePicture(dpy, w->alphaPict); + w->alphaPict = None; + } + if (w->shadowPict) { + XRenderFreePicture(dpy, w->shadowPict); + w->shadowPict = None; + } + if (w->shadow) { + XRenderFreePicture(dpy, w->shadow); + w->shadow = None; + } + if (w->damage != None) { + set_ignore(dpy, NextRequest(dpy)); + XDamageDestroy(dpy, w->damage); + w->damage = None; + } + cleanup_fade(dpy, w); + free(w); + break; + } + } +} + +static void destroy_callback(Display *dpy, win *w, Bool gone) +{ + finish_destroy_win(dpy, w->id, gone); +} + +static void destroy_win(Display *dpy, Window id, Bool gone, Bool doFade) +{ + win *w = find_win(dpy, id); + if (w && w->pixmap && doFade && fadeWindows) { + set_fade(dpy, w, w->opacity * 1.0 / OPAQUE, 0.0, fade_out_step, destroy_callback, gone, False, + True); + } else { + finish_destroy_win(dpy, id, gone); + } +} + +static void damage_win(Display *dpy, XDamageNotifyEvent *de) +{ + win *w = find_win(dpy, de->drawable); + + if (!w) { + return; + } + repair_win(dpy, w); +} + +static void shape_win(Display *dpy, XShapeEvent *se) +{ + win *w = find_win(dpy, se->window); + + if (!w) { + return; + } + if (se->kind == ShapeClip || se->kind == ShapeBounding) { + XserverRegion region0; + XserverRegion region1; + + clipChanged = True; + + region0 = XFixesCreateRegion(dpy, &w->shape_bounds, 1); + + if (se->shaped == True) { + w->shaped = True; + w->shape_bounds.x = w->a.x + se->x; + w->shape_bounds.y = w->a.y + se->y; + w->shape_bounds.width = se->width; + w->shape_bounds.height = se->height; + } else { + w->shaped = False; + w->shape_bounds.x = w->a.x; + w->shape_bounds.y = w->a.y; + w->shape_bounds.width = w->a.width; + w->shape_bounds.height = w->a.height; + } + + region1 = XFixesCreateRegion(dpy, &w->shape_bounds, 1); + XFixesUnionRegion(dpy, region0, region0, region1); + XFixesDestroyRegion(dpy, region1); + + /* ask for repaint of the old and new region */ + paint_all(dpy, region0); + } +} + +static int error(Display *dpy, XErrorEvent *ev) +{ + int o; + const char *name = NULL; + static char buffer[256]; + + if (should_ignore(dpy, ev->serial)) { + return 0; + } + + if (ev->request_code == composite_opcode && ev->minor_code == X_CompositeRedirectSubwindows) { + fprintf(stderr, "Another composite manager is already running\n"); + exit(1); + } + + o = ev->error_code - xfixes_error; + switch (o) { + case BadRegion: + name = "BadRegion"; + break; + default: + break; + } + o = ev->error_code - damage_error; + switch (o) { + case BadDamage: + name = "BadDamage"; + break; + default: + break; + } + o = ev->error_code - render_error; + switch (o) { + case BadPictFormat: + name = "BadPictFormat"; + break; + case BadPicture: + name = "BadPicture"; + break; + case BadPictOp: + name = "BadPictOp"; + break; + case BadGlyphSet: + name = "BadGlyphSet"; + break; + case BadGlyph: + name = "BadGlyph"; + break; + default: + break; + } + + if (name == NULL) { + buffer[0] = '\0'; + XGetErrorText(dpy, ev->error_code, buffer, sizeof(buffer)); + name = buffer; + } + + fprintf(stderr, "error %d: %s request %d minor %d serial %lu\n", ev->error_code, + (strlen(name) > 0) ? name : "unknown", ev->request_code, ev->minor_code, ev->serial); + + return 0; +} + +static void expose_root(Display *dpy, Window rootwin, XRectangle *rects, int nrects) +{ + XserverRegion region = XFixesCreateRegion(dpy, rects, nrects); + + add_damage(dpy, region); +} + +static void _X_COLD _X_NORETURN usage(const char *program) +{ + fprintf(stderr, "usage: %s [options]\n%s\n", program, + "Options:\n" + " -d display\n" + " Specifies which display should be managed.\n" + " -r radius\n" + " Specifies the blur radius for client-side shadows. (default 12)\n" + " -o opacity\n" + " Specifies the translucency for client-side shadows. (default .75)\n" + " -l left-offset\n" + " Specifies the left offset for client-side shadows. (default -15)\n" + " -t top-offset\n" + " Specifies the top offset for clinet-side shadows. (default -15)\n" + " -I fade-in-step\n" + " Specifies the opacity change between steps while fading in. (default 0.028)\n" + " -O fade-out-step\n" + " Specifies the opacity change between steps while fading out. (default 0.03)\n" + " -D fade-delta-time\n" + " Specifies the time between steps in a fade in milliseconds. (default 10)\n" + " -a\n" + " Use automatic server-side compositing. Faster, but no special effects.\n" + " -c\n" + " Draw client-side shadows with fuzzy edges.\n" + " -C\n" + " Avoid drawing shadows on dock/panel windows.\n" + " -f\n" + " Fade windows in/out when opening/closing.\n" + " -F\n" + " Fade windows during opacity changes.\n" + " -n\n" + " Normal client-side compositing with transparency support\n" + " -s\n" + " Draw server-side shadows with sharp edges.\n" + " -S\n" + " Enable synchronous operation (for debugging).\n"); + exit(1); +} + +static Bool register_cm(Display *dpy) +{ + Window w; + Atom a; + static char net_wm_cm[] = "_NET_WM_CM_Sxx"; + + snprintf(net_wm_cm, sizeof(net_wm_cm), "_NET_WM_CM_S%d", scr); + a = XInternAtom(dpy, net_wm_cm, False); + + w = XGetSelectionOwner(dpy, a); + if (w != None) { + XTextProperty tp; + char **strs; + int count; + Atom winNameAtom = XInternAtom(dpy, "_NET_WM_NAME", False); + + if (!XGetTextProperty(dpy, w, &tp, winNameAtom) && !XGetTextProperty(dpy, w, &tp, XA_WM_NAME)) { + fprintf(stderr, "Another composite manager is already running (0x%lx)\n", (unsigned long)w); + return False; + } + if (XmbTextPropertyToTextList(dpy, &tp, &strs, &count) == Success) { + fprintf(stderr, "Another composite manager is already running (%s)\n", strs[0]); + + XFreeStringList(strs); + } + + XFree(tp.value); + + return False; + } + + w = XCreateSimpleWindow(dpy, RootWindow(dpy, scr), 0, 0, 1, 1, 0, None, None); + + Xutf8SetWMProperties(dpy, w, "xcompmgr", "xcompmgr", NULL, 0, NULL, NULL, NULL); + + XSetSelectionOwner(dpy, a, w, 0); + + return True; +} + +int compose_main(int argc, char **argv) +{ + Display *dpy; + XEvent ev; + Window root_return, parent_return; + Window *children; + unsigned int nchildren; + XRenderPictureAttributes pa; + XRectangle *expose_rects = NULL; + int size_expose = 0; + int n_expose = 0; + struct pollfd ufd; + int p; + int composite_major, composite_minor; + char *display = NULL; + int o; + + while ((o = getopt(argc, argv, "D:I:O:d:r:o:l:t:scnfFCaS")) != -1) { + switch (o) { + case 'd': + display = optarg; + break; + case 'D': + fade_delta = atoi(optarg); + if (fade_delta < 1) { + fade_delta = 10; + } + break; + case 'I': + fade_in_step = atof(optarg); + if (fade_in_step <= 0) { + fade_in_step = 0.01; + } + break; + case 'O': + fade_out_step = atof(optarg); + if (fade_out_step <= 0) { + fade_out_step = 0.01; + } + break; + case 's': + compMode = CompServerShadows; + break; + case 'c': + compMode = CompClientShadows; + break; + case 'C': + excludeDockShadows = True; + break; + case 'n': + compMode = CompSimple; + break; + case 'f': + fadeWindows = True; + break; + case 'F': + fadeTrans = True; + break; + case 'a': + autoRedirect = True; + break; + case 'S': + synchronize = True; + break; + case 'r': + shadowRadius = atoi(optarg); + break; + case 'o': + shadowOpacity = atof(optarg); + break; + case 'l': + shadowOffsetX = atoi(optarg); + break; + case 't': + shadowOffsetY = atoi(optarg); + break; + default: + usage(argv[0]); + break; + } + } + + dpy = XOpenDisplay(display); + if (!dpy) { + fprintf(stderr, "Can't open display\n"); + exit(1); + } + XSetErrorHandler(error); + if (synchronize) { + XSynchronize(dpy, 1); + } + scr = DefaultScreen(dpy); + root = RootWindow(dpy, scr); + + if (!XRenderQueryExtension(dpy, &render_event, &render_error)) { + fprintf(stderr, "No render extension\n"); + exit(1); + } + if (!XQueryExtension(dpy, COMPOSITE_NAME, &composite_opcode, &composite_event, + &composite_error)) { + fprintf(stderr, "No composite extension\n"); + exit(1); + } + XCompositeQueryVersion(dpy, &composite_major, &composite_minor); + if (composite_major > 0 || composite_minor >= 2) { + hasNamePixmap = True; + } + if (!XDamageQueryExtension(dpy, &damage_event, &damage_error)) { + fprintf(stderr, "No damage extension\n"); + exit(1); + } + if (!XFixesQueryExtension(dpy, &xfixes_event, &xfixes_error)) { + fprintf(stderr, "No XFixes extension\n"); + exit(1); + } + if (!XShapeQueryExtension(dpy, &xshape_event, &xshape_error)) { + fprintf(stderr, "No XShape extension\n"); + exit(1); + } + + if (!register_cm(dpy)) { + exit(1); + } + + /* get atoms */ + opacityAtom = XInternAtom(dpy, OPACITY_PROP, False); + winTypeAtom = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False); + winDesktopAtom = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DESKTOP", False); + winDockAtom = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DOCK", False); + winToolbarAtom = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_TOOLBAR", False); + winMenuAtom = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_MENU", False); + winUtilAtom = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_UTILITY", False); + winSplashAtom = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_SPLASH", False); + winDialogAtom = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False); + winNormalAtom = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_NORMAL", False); + + pa.subwindow_mode = IncludeInferiors; + + if (compMode == CompClientShadows) { + gaussianMap = make_gaussian_map(dpy, shadowRadius); + presum_gaussian(gaussianMap); + } + + root_width = DisplayWidth(dpy, scr); + root_height = DisplayHeight(dpy, scr); + + rootPicture = XRenderCreatePicture( + dpy, root, XRenderFindVisualFormat(dpy, DefaultVisual(dpy, scr)), CPSubwindowMode, &pa); + blackPicture = solid_picture(dpy, True, 1, 0, 0, 0); + if (compMode == CompServerShadows) { + transBlackPicture = solid_picture(dpy, True, 0.3, 0, 0, 0); + } + allDamage = None; + clipChanged = True; + XGrabServer(dpy); + if (autoRedirect) { + XCompositeRedirectSubwindows(dpy, root, CompositeRedirectAutomatic); + } else { + XCompositeRedirectSubwindows(dpy, root, CompositeRedirectManual); + XSelectInput(dpy, root, + SubstructureNotifyMask | ExposureMask | StructureNotifyMask | PropertyChangeMask); + XShapeSelectInput(dpy, root, ShapeNotifyMask); + XQueryTree(dpy, root, &root_return, &parent_return, &children, &nchildren); + for (unsigned int i = 0; i < nchildren; i++) + add_win(dpy, children[i], i ? children[i - 1] : None); + XFree(children); + } + XUngrabServer(dpy); + ufd.fd = ConnectionNumber(dpy); + ufd.events = POLLIN; + if (!autoRedirect) { + paint_all(dpy, None); + } + for (;;) { + do { + if (autoRedirect) { + XFlush(dpy); + } + if (!QLength(dpy)) { + if (poll(&ufd, 1, fade_timeout()) == 0) { + run_fades(dpy); + break; + } + } + + XNextEvent(dpy, &ev); + if ((ev.type & 0x7f) != KeymapNotify) { + discard_ignore(dpy, ev.xany.serial); + } + + if (!autoRedirect) { + switch (ev.type) { + case CreateNotify: + add_win(dpy, ev.xcreatewindow.window, 0); + break; + case ConfigureNotify: + configure_win(dpy, &ev.xconfigure); + break; + case DestroyNotify: + destroy_win(dpy, ev.xdestroywindow.window, True, True); + break; + case MapNotify: + map_win(dpy, ev.xmap.window, ev.xmap.serial, True); + break; + case UnmapNotify: + unmap_win(dpy, ev.xunmap.window, True); + break; + case ReparentNotify: + if (ev.xreparent.parent == root) + add_win(dpy, ev.xreparent.window, 0); + else + destroy_win(dpy, ev.xreparent.window, False, True); + break; + case CirculateNotify: + circulate_win(dpy, &ev.xcirculate); + break; + case Expose: + if (ev.xexpose.window == root) { + int more = ev.xexpose.count + 1; + if (n_expose == size_expose) { + if (expose_rects) { + expose_rects = realloc(expose_rects, (size_expose + more) * sizeof(XRectangle)); + size_expose += more; + } else { + expose_rects = malloc(more * sizeof(XRectangle)); + size_expose = more; + } + } + expose_rects[n_expose].x = ev.xexpose.x; + expose_rects[n_expose].y = ev.xexpose.y; + expose_rects[n_expose].width = ev.xexpose.width; + expose_rects[n_expose].height = ev.xexpose.height; + n_expose++; + if (ev.xexpose.count == 0) { + expose_root(dpy, root, expose_rects, n_expose); + n_expose = 0; + } + } + break; + case PropertyNotify: + for (p = 0; backgroundProps[p]; p++) { + if (ev.xproperty.atom == XInternAtom(dpy, backgroundProps[p], False)) { + if (rootTile) { + XClearArea(dpy, root, 0, 0, 0, 0, True); + XRenderFreePicture(dpy, rootTile); + rootTile = None; + break; + } + } + } + /* check if Trans property was changed */ + if (ev.xproperty.atom == opacityAtom) { + /* reset mode and redraw window */ + win *w = find_win(dpy, ev.xproperty.window); + if (w) { + if (fadeTrans) { + double start, finish, step; + start = w->opacity * 1.0 / OPAQUE; + finish = get_opacity_percent(dpy, w, 1.0); + if (start > finish) { + step = fade_in_step; + } else { + step = fade_out_step; + } + set_fade(dpy, w, start, finish, step, NULL, False, True, False); + } else { + w->opacity = get_opacity_prop(dpy, w, OPAQUE); + determine_mode(dpy, w); + if (w->shadow) { + XRenderFreePicture(dpy, w->shadow); + w->shadow = None; + w->extents = win_extents(dpy, w); + } + } + } + } + break; + default: + if (ev.type == damage_event + XDamageNotify) { + damage_win(dpy, (XDamageNotifyEvent *)&ev); + } else if (ev.type == xshape_event + ShapeNotify) { + shape_win(dpy, (XShapeEvent *)&ev); + } + break; + } + } + } while (QLength(dpy)); + + if (allDamage && !autoRedirect) { + static int paint; + paint_all(dpy, allDamage); + paint++; + XSync(dpy, False); + allDamage = None; + clipChanged = False; + } + } +} From 2eb341cf331752073c1a8a13489c10a1daaa70d5 Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Thu, 12 Oct 2023 18:20:18 +0300 Subject: [PATCH 05/67] compositor added to the build process. --- Applications/Workspace/GNUmakefile.WM | 3 +- Applications/Workspace/GNUmakefile.preamble | 1 + Applications/Workspace/WM/wmcomposer.c | 677 +++++++++++--------- 3 files changed, 392 insertions(+), 289 deletions(-) diff --git a/Applications/Workspace/GNUmakefile.WM b/Applications/Workspace/GNUmakefile.WM index f54f9ee9c..c9dd3cb02 100644 --- a/Applications/Workspace/GNUmakefile.WM +++ b/Applications/Workspace/GNUmakefile.WM @@ -69,7 +69,8 @@ $(APP_NAME)_C_FILES += \ $(WM_DIR)/xrandr.c \ $(WM_DIR)/xutil.c \ $(WM_DIR)/xmodifier.c \ - $(WM_DIR)/xdnd.c + $(WM_DIR)/xdnd.c \ + $(WM_DIR)/wmcomposer.c ifeq ($(findstring freebsd, $(GNUSTEP_TARGET_OS)), freebsd) $(APP_NAME)_C_FILES += $(WM_DIR)/osdep_bsd.c diff --git a/Applications/Workspace/GNUmakefile.preamble b/Applications/Workspace/GNUmakefile.preamble index 2f7d3cfda..385e6bb9c 100644 --- a/Applications/Workspace/GNUmakefile.preamble +++ b/Applications/Workspace/GNUmakefile.preamble @@ -33,3 +33,4 @@ ADDITIONAL_CFLAGS += -DNDEBUG -D_XOPEN_SOURCE=600 -D_GNU_SOURCE ADDITIONAL_INCLUDE_DIRS += -I./$(WM_DIR) -I./$(WM_DIR)/core ADDITIONAL_INCLUDE_DIRS += `pkg-config --cflags fontconfig` ADDITIONAL_GUI_LIBS += -lfontconfig -lXft -lwraster -lXext -lXrandr -lXfixes -lXcursor +ADDITIONAL_GUI_LIBS += -lXrender -lXdamage -lXcomposite diff --git a/Applications/Workspace/WM/wmcomposer.c b/Applications/Workspace/WM/wmcomposer.c index e8ac7e014..6bb8804f2 100644 --- a/Applications/Workspace/WM/wmcomposer.c +++ b/Applications/Workspace/WM/wmcomposer.c @@ -91,6 +91,7 @@ typedef struct _fade { Bool gone; } fade; +static Display *dpy; static win *list; static fade *fades; static int scr; @@ -158,14 +159,13 @@ static int shadowOffsetX = -15; static int shadowOffsetY = -15; static double shadowOpacity = .75; +static Bool fadeWindows = False; +static Bool fadeTrans = False; static double fade_in_step = 0.028; static double fade_out_step = 0.03; static int fade_delta = 10; static int fade_time = 0; -static Bool fadeWindows = False; static Bool excludeDockShadows = False; -static Bool fadeTrans = False; - static Bool autoRedirect = False; /* For shadow precomputation */ @@ -339,7 +339,7 @@ static void run_fades(Display *dpy) } // ---------------------------------------------------------------------------------------------- -// Gaussian +// Gaussian utilities // ---------------------------------------------------------------------------------------------- static double gaussian(double r, double x, double y) { @@ -627,12 +627,13 @@ static Picture shadow_picture(Display *dpy, double opacity, Picture alpha_pict, } -static Picture solid_picture(Display *dpy, Bool argb, double a, double r, double g, double b) +static Picture wComposerCreateSolidPicture(Display *dpy, Bool argb, double a, double r, double g, double b) { Pixmap pixmap; Picture picture; XRenderPictureAttributes pa; XRenderColor c; + XRenderPictFormat *pictureFormat; pixmap = XCreatePixmap(dpy, root, 1, 1, argb ? 32 : 8); if (!pixmap) { @@ -640,9 +641,8 @@ static Picture solid_picture(Display *dpy, Bool argb, double a, double r, double } pa.repeat = True; - picture = XRenderCreatePicture( - dpy, pixmap, XRenderFindStandardFormat(dpy, argb ? PictStandardARGB32 : PictStandardA8), - CPRepeat, &pa); + pictureFormat = XRenderFindStandardFormat(dpy, argb ? PictStandardARGB32 : PictStandardA8); + picture = XRenderCreatePicture(dpy, pixmap, pictureFormat, CPRepeat, &pa); if (!picture) { XFreePixmap(dpy, pixmap); return None; @@ -657,6 +657,9 @@ static Picture solid_picture(Display *dpy, Bool argb, double a, double r, double return picture; } +// ---------------------------------------------------------------------------------------------- +// Events +// ---------------------------------------------------------------------------------------------- static void discard_ignore(Display *dpy, unsigned long sequence) { while (ignore_head) { @@ -746,7 +749,8 @@ static Picture root_tile(Display *dpy) if (fill) { XRenderColor c; - c.red = c.green = c.blue = 0x8080; + // c.red = c.green = c.blue = 0x8080; + c.red = c.green = c.blue = 0x6363; c.alpha = 0xffff; XRenderFillRectangle(dpy, PictOpSrc, picture, &c, 0, 0, 1, 1); } @@ -834,7 +838,7 @@ static XserverRegion border_size(Display *dpy, win *w) return border; } -static void paint_all(Display *dpy, XserverRegion region) +static void wComposerPaintAll(Display *dpy, XserverRegion region) { win *w; win *t = NULL; @@ -932,7 +936,7 @@ static void paint_all(Display *dpy, XserverRegion region) break; set_ignore(dpy, NextRequest(dpy)); if (w->opacity != OPAQUE && !w->shadowPict) - w->shadowPict = solid_picture(dpy, True, (double)w->opacity / OPAQUE * 0.3, 0, 0, 0); + w->shadowPict = wComposerCreateSolidPicture(dpy, True, (double)w->opacity / OPAQUE * 0.3, 0, 0, 0); XRenderComposite(dpy, PictOpOver, w->shadowPict ? w->shadowPict : transBlackPicture, w->picture, rootBuffer, 0, 0, 0, 0, w->a.x + w->shadow_dx, w->a.y + w->shadow_dy, w->shadow_width, w->shadow_height); @@ -947,7 +951,7 @@ static void paint_all(Display *dpy, XserverRegion region) break; } if (w->opacity != OPAQUE && !w->alphaPict) { - w->alphaPict = solid_picture(dpy, False, (double)w->opacity / OPAQUE, 0, 0, 0); + w->alphaPict = wComposerCreateSolidPicture(dpy, False, (double)w->opacity / OPAQUE, 0, 0, 0); } if (w->mode == WINDOW_TRANS) { int x, y, wid, hei; @@ -1018,7 +1022,7 @@ static void repair_win(Display *dpy, win *w) w->damaged = 1; } -static void map_win(Display *dpy, Window id, unsigned long sequence, Bool doFade) +static void wComposerMapWindow(Display *dpy, Window id, unsigned long sequence, Bool doFade) { win *w = find_win(dpy, id); @@ -1083,7 +1087,7 @@ static void finish_unmap_win(Display *dpy, win *w) static void unmap_callback(Display *dpy, win *w, Bool gone) { finish_unmap_win(dpy, w); } -static void unmap_win(Display *dpy, Window id, Bool doFade) +static void wComposerUnmapWindow(Display *dpy, Window id, Bool doFade) { win *w = find_win(dpy, id); if (!w) { @@ -1224,7 +1228,7 @@ static Atom determine_wintype(Display *dpy, Window w) return winNormalAtom; } -static void add_win(Display *dpy, Window id, Window prev) +static void wComposerAddWindow(Display *dpy, Window id, Window prev) { win *new = malloc(sizeof(win)); win **p; @@ -1281,7 +1285,7 @@ static void add_win(Display *dpy, Window id, Window prev) new->next = *p; *p = new; if (new->a.map_state == IsViewable) { - map_win(dpy, id, new->damage_sequence - 1, True); + wComposerMapWindow(dpy, id, new->damage_sequence - 1, True); } } @@ -1316,7 +1320,7 @@ static void restack_win(Display *dpy, win *w, Window new_above) } } -static void configure_win(Display *dpy, XConfigureEvent *ce) +static void wComposerConfigureWindow(Display *dpy, XConfigureEvent *ce) { win *w = find_win(dpy, ce->window); XserverRegion damage = None; @@ -1436,7 +1440,7 @@ static void destroy_callback(Display *dpy, win *w, Bool gone) finish_destroy_win(dpy, w->id, gone); } -static void destroy_win(Display *dpy, Window id, Bool gone, Bool doFade) +static void wComposerRemoveWindow(Display *dpy, Window id, Bool gone, Bool doFade) { win *w = find_win(dpy, id); if (w && w->pixmap && doFade && fadeWindows) { @@ -1447,7 +1451,7 @@ static void destroy_win(Display *dpy, Window id, Bool gone, Bool doFade) } } -static void damage_win(Display *dpy, XDamageNotifyEvent *de) +static void wComposerProcessDamageEvent(Display *dpy, XDamageNotifyEvent *de) { win *w = find_win(dpy, de->drawable); @@ -1491,23 +1495,30 @@ static void shape_win(Display *dpy, XShapeEvent *se) XFixesDestroyRegion(dpy, region1); /* ask for repaint of the old and new region */ - paint_all(dpy, region0); + wComposerPaintAll(dpy, region0); } } -static int error(Display *dpy, XErrorEvent *ev) +static void expose_root(Display *dpy, Window rootwin, XRectangle *rects, int nrects) +{ + XserverRegion region = XFixesCreateRegion(dpy, rects, nrects); + + add_damage(dpy, region); +} + +Bool wComposerErrorHandler(Display *dpy, XErrorEvent *ev) { int o; const char *name = NULL; static char buffer[256]; if (should_ignore(dpy, ev->serial)) { - return 0; + return True; } if (ev->request_code == composite_opcode && ev->minor_code == X_CompositeRedirectSubwindows) { fprintf(stderr, "Another composite manager is already running\n"); - exit(1); + return False; } o = ev->error_code - xfixes_error; @@ -1548,276 +1559,143 @@ static int error(Display *dpy, XErrorEvent *ev) } if (name == NULL) { + return False; + } else { buffer[0] = '\0'; XGetErrorText(dpy, ev->error_code, buffer, sizeof(buffer)); name = buffer; - } - - fprintf(stderr, "error %d: %s request %d minor %d serial %lu\n", ev->error_code, - (strlen(name) > 0) ? name : "unknown", ev->request_code, ev->minor_code, ev->serial); - - return 0; -} - -static void expose_root(Display *dpy, Window rootwin, XRectangle *rects, int nrects) -{ - XserverRegion region = XFixesCreateRegion(dpy, rects, nrects); - - add_damage(dpy, region); -} - -static void _X_COLD _X_NORETURN usage(const char *program) -{ - fprintf(stderr, "usage: %s [options]\n%s\n", program, - "Options:\n" - " -d display\n" - " Specifies which display should be managed.\n" - " -r radius\n" - " Specifies the blur radius for client-side shadows. (default 12)\n" - " -o opacity\n" - " Specifies the translucency for client-side shadows. (default .75)\n" - " -l left-offset\n" - " Specifies the left offset for client-side shadows. (default -15)\n" - " -t top-offset\n" - " Specifies the top offset for clinet-side shadows. (default -15)\n" - " -I fade-in-step\n" - " Specifies the opacity change between steps while fading in. (default 0.028)\n" - " -O fade-out-step\n" - " Specifies the opacity change between steps while fading out. (default 0.03)\n" - " -D fade-delta-time\n" - " Specifies the time between steps in a fade in milliseconds. (default 10)\n" - " -a\n" - " Use automatic server-side compositing. Faster, but no special effects.\n" - " -c\n" - " Draw client-side shadows with fuzzy edges.\n" - " -C\n" - " Avoid drawing shadows on dock/panel windows.\n" - " -f\n" - " Fade windows in/out when opening/closing.\n" - " -F\n" - " Fade windows during opacity changes.\n" - " -n\n" - " Normal client-side compositing with transparency support\n" - " -s\n" - " Draw server-side shadows with sharp edges.\n" - " -S\n" - " Enable synchronous operation (for debugging).\n"); - exit(1); -} - -static Bool register_cm(Display *dpy) -{ - Window w; - Atom a; - static char net_wm_cm[] = "_NET_WM_CM_Sxx"; - - snprintf(net_wm_cm, sizeof(net_wm_cm), "_NET_WM_CM_S%d", scr); - a = XInternAtom(dpy, net_wm_cm, False); - w = XGetSelectionOwner(dpy, a); - if (w != None) { - XTextProperty tp; - char **strs; - int count; - Atom winNameAtom = XInternAtom(dpy, "_NET_WM_NAME", False); - - if (!XGetTextProperty(dpy, w, &tp, winNameAtom) && !XGetTextProperty(dpy, w, &tp, XA_WM_NAME)) { - fprintf(stderr, "Another composite manager is already running (0x%lx)\n", (unsigned long)w); - return False; - } - if (XmbTextPropertyToTextList(dpy, &tp, &strs, &count) == Success) { - fprintf(stderr, "Another composite manager is already running (%s)\n", strs[0]); - - XFreeStringList(strs); - } - - XFree(tp.value); - - return False; + fprintf(stderr, "error %d: %s request %d minor %d serial %lu\n", ev->error_code, + (strlen(name) > 0) ? name : "unknown", ev->request_code, ev->minor_code, ev->serial); } - w = XCreateSimpleWindow(dpy, RootWindow(dpy, scr), 0, 0, 1, 1, 0, None, None); - - Xutf8SetWMProperties(dpy, w, "xcompmgr", "xcompmgr", NULL, 0, NULL, NULL, NULL); - - XSetSelectionOwner(dpy, a, w, 0); - return True; } -int compose_main(int argc, char **argv) +// static XRectangle *expose_rects = NULL; +// static int size_expose = 0; +// static int n_expose = 0; +// static int p; +// void wComposerProcessEvent(Display *dpy, XEvent ev) +// { +// if (!autoRedirect) { +// switch (ev.type) { +// case CreateNotify: +// wComposerAddWindow(dpy, ev.xcreatewindow.window, 0); +// break; +// case ConfigureNotify: +// wComposerConfigureWindow(dpy, &ev.xconfigure); +// break; +// case DestroyNotify: +// wComposerRemoveWindow(dpy, ev.xdestroywindow.window, True, True); +// break; +// case MapNotify: +// wComposerMapWindow(dpy, ev.xmap.window, ev.xmap.serial, True); +// break; +// case UnmapNotify: +// wComposerUnmapWindow(dpy, ev.xunmap.window, True); +// break; +// case ReparentNotify: +// if (ev.xreparent.parent == root) { +// wComposerAddWindow(dpy, ev.xreparent.window, 0); +// } else { +// wComposerRemoveWindow(dpy, ev.xreparent.window, False, True); +// } +// break; +// case CirculateNotify: +// circulate_win(dpy, &ev.xcirculate); +// break; +// case Expose: +// if (ev.xexpose.window == root) { +// int more = ev.xexpose.count + 1; +// if (n_expose == size_expose) { +// if (expose_rects) { +// expose_rects = realloc(expose_rects, (size_expose + more) * sizeof(XRectangle)); +// size_expose += more; +// } else { +// expose_rects = malloc(more * sizeof(XRectangle)); +// size_expose = more; +// } +// } +// expose_rects[n_expose].x = ev.xexpose.x; +// expose_rects[n_expose].y = ev.xexpose.y; +// expose_rects[n_expose].width = ev.xexpose.width; +// expose_rects[n_expose].height = ev.xexpose.height; +// n_expose++; +// if (ev.xexpose.count == 0) { +// expose_root(dpy, root, expose_rects, n_expose); +// n_expose = 0; +// } +// } +// break; +// case PropertyNotify: +// for (p = 0; backgroundProps[p]; p++) { +// if (ev.xproperty.atom == XInternAtom(dpy, backgroundProps[p], False)) { +// if (rootTile) { +// XClearArea(dpy, root, 0, 0, 0, 0, True); +// XRenderFreePicture(dpy, rootTile); +// rootTile = None; +// break; +// } +// } +// } +// /* check if Trans property was changed */ +// if (ev.xproperty.atom == opacityAtom) { +// /* reset mode and redraw window */ +// win *w = find_win(dpy, ev.xproperty.window); +// if (w) { +// if (fadeTrans) { +// double start, finish, step; +// start = w->opacity * 1.0 / OPAQUE; +// finish = get_opacity_percent(dpy, w, 1.0); +// if (start > finish) +// step = fade_in_step; +// else +// step = fade_out_step; +// set_fade(dpy, w, start, finish, step, NULL, False, True, False); +// } else { +// w->opacity = get_opacity_prop(dpy, w, OPAQUE); +// determine_mode(dpy, w); +// if (w->shadow) { +// XRenderFreePicture(dpy, w->shadow); +// w->shadow = None; +// w->extents = win_extents(dpy, w); +// } +// } +// } +// } +// break; +// default: +// if (ev.type == damage_event + XDamageNotify) { +// fprintf(stderr, "XDamageNotify"); +// damage_win(dpy, (XDamageNotifyEvent *)&ev); +// } else if (ev.type == xshape_event + ShapeNotify) { +// fprintf(stderr, "ShapeNotify"); +// shape_win(dpy, (XShapeEvent *)&ev); +// } +// break; +// } +// } +// } + +#include "WM/core/log_utils.h" +void wComposerRunLoop() { - Display *dpy; + struct pollfd ufd; XEvent ev; - Window root_return, parent_return; - Window *children; - unsigned int nchildren; - XRenderPictureAttributes pa; XRectangle *expose_rects = NULL; int size_expose = 0; int n_expose = 0; - struct pollfd ufd; int p; - int composite_major, composite_minor; - char *display = NULL; - int o; - - while ((o = getopt(argc, argv, "D:I:O:d:r:o:l:t:scnfFCaS")) != -1) { - switch (o) { - case 'd': - display = optarg; - break; - case 'D': - fade_delta = atoi(optarg); - if (fade_delta < 1) { - fade_delta = 10; - } - break; - case 'I': - fade_in_step = atof(optarg); - if (fade_in_step <= 0) { - fade_in_step = 0.01; - } - break; - case 'O': - fade_out_step = atof(optarg); - if (fade_out_step <= 0) { - fade_out_step = 0.01; - } - break; - case 's': - compMode = CompServerShadows; - break; - case 'c': - compMode = CompClientShadows; - break; - case 'C': - excludeDockShadows = True; - break; - case 'n': - compMode = CompSimple; - break; - case 'f': - fadeWindows = True; - break; - case 'F': - fadeTrans = True; - break; - case 'a': - autoRedirect = True; - break; - case 'S': - synchronize = True; - break; - case 'r': - shadowRadius = atoi(optarg); - break; - case 'o': - shadowOpacity = atof(optarg); - break; - case 'l': - shadowOffsetX = atoi(optarg); - break; - case 't': - shadowOffsetY = atoi(optarg); - break; - default: - usage(argv[0]); - break; - } - } - - dpy = XOpenDisplay(display); - if (!dpy) { - fprintf(stderr, "Can't open display\n"); - exit(1); - } - XSetErrorHandler(error); - if (synchronize) { - XSynchronize(dpy, 1); - } - scr = DefaultScreen(dpy); - root = RootWindow(dpy, scr); - - if (!XRenderQueryExtension(dpy, &render_event, &render_error)) { - fprintf(stderr, "No render extension\n"); - exit(1); - } - if (!XQueryExtension(dpy, COMPOSITE_NAME, &composite_opcode, &composite_event, - &composite_error)) { - fprintf(stderr, "No composite extension\n"); - exit(1); - } - XCompositeQueryVersion(dpy, &composite_major, &composite_minor); - if (composite_major > 0 || composite_minor >= 2) { - hasNamePixmap = True; - } - if (!XDamageQueryExtension(dpy, &damage_event, &damage_error)) { - fprintf(stderr, "No damage extension\n"); - exit(1); - } - if (!XFixesQueryExtension(dpy, &xfixes_event, &xfixes_error)) { - fprintf(stderr, "No XFixes extension\n"); - exit(1); - } - if (!XShapeQueryExtension(dpy, &xshape_event, &xshape_error)) { - fprintf(stderr, "No XShape extension\n"); - exit(1); - } - if (!register_cm(dpy)) { - exit(1); - } - - /* get atoms */ - opacityAtom = XInternAtom(dpy, OPACITY_PROP, False); - winTypeAtom = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False); - winDesktopAtom = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DESKTOP", False); - winDockAtom = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DOCK", False); - winToolbarAtom = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_TOOLBAR", False); - winMenuAtom = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_MENU", False); - winUtilAtom = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_UTILITY", False); - winSplashAtom = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_SPLASH", False); - winDialogAtom = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False); - winNormalAtom = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_NORMAL", False); + WMLogError("Composer: Entering runloop with X connection: %i", ConnectionNumber(dpy)); - pa.subwindow_mode = IncludeInferiors; - - if (compMode == CompClientShadows) { - gaussianMap = make_gaussian_map(dpy, shadowRadius); - presum_gaussian(gaussianMap); - } - - root_width = DisplayWidth(dpy, scr); - root_height = DisplayHeight(dpy, scr); - - rootPicture = XRenderCreatePicture( - dpy, root, XRenderFindVisualFormat(dpy, DefaultVisual(dpy, scr)), CPSubwindowMode, &pa); - blackPicture = solid_picture(dpy, True, 1, 0, 0, 0); - if (compMode == CompServerShadows) { - transBlackPicture = solid_picture(dpy, True, 0.3, 0, 0, 0); - } - allDamage = None; - clipChanged = True; - XGrabServer(dpy); - if (autoRedirect) { - XCompositeRedirectSubwindows(dpy, root, CompositeRedirectAutomatic); - } else { - XCompositeRedirectSubwindows(dpy, root, CompositeRedirectManual); - XSelectInput(dpy, root, - SubstructureNotifyMask | ExposureMask | StructureNotifyMask | PropertyChangeMask); - XShapeSelectInput(dpy, root, ShapeNotifyMask); - XQueryTree(dpy, root, &root_return, &parent_return, &children, &nchildren); - for (unsigned int i = 0; i < nchildren; i++) - add_win(dpy, children[i], i ? children[i - 1] : None); - XFree(children); - } - XUngrabServer(dpy); ufd.fd = ConnectionNumber(dpy); ufd.events = POLLIN; if (!autoRedirect) { - paint_all(dpy, None); + wComposerPaintAll(dpy, None); } + for (;;) { do { if (autoRedirect) { @@ -1829,34 +1707,34 @@ int compose_main(int argc, char **argv) break; } } - XNextEvent(dpy, &ev); if ((ev.type & 0x7f) != KeymapNotify) { discard_ignore(dpy, ev.xany.serial); } - + // wComposerProcessEvent(dpy, ev); if (!autoRedirect) { switch (ev.type) { case CreateNotify: - add_win(dpy, ev.xcreatewindow.window, 0); + wComposerAddWindow(dpy, ev.xcreatewindow.window, 0); break; case ConfigureNotify: - configure_win(dpy, &ev.xconfigure); + wComposerConfigureWindow(dpy, &ev.xconfigure); break; case DestroyNotify: - destroy_win(dpy, ev.xdestroywindow.window, True, True); + wComposerRemoveWindow(dpy, ev.xdestroywindow.window, True, True); break; case MapNotify: - map_win(dpy, ev.xmap.window, ev.xmap.serial, True); + wComposerMapWindow(dpy, ev.xmap.window, ev.xmap.serial, True); break; case UnmapNotify: - unmap_win(dpy, ev.xunmap.window, True); + wComposerUnmapWindow(dpy, ev.xunmap.window, True); break; case ReparentNotify: - if (ev.xreparent.parent == root) - add_win(dpy, ev.xreparent.window, 0); - else - destroy_win(dpy, ev.xreparent.window, False, True); + if (ev.xreparent.parent == root) { + wComposerAddWindow(dpy, ev.xreparent.window, 0); + } else { + wComposerRemoveWindow(dpy, ev.xreparent.window, False, True); + } break; case CirculateNotify: circulate_win(dpy, &ev.xcirculate); @@ -1904,11 +1782,10 @@ int compose_main(int argc, char **argv) double start, finish, step; start = w->opacity * 1.0 / OPAQUE; finish = get_opacity_percent(dpy, w, 1.0); - if (start > finish) { + if (start > finish) step = fade_in_step; - } else { + else step = fade_out_step; - } set_fade(dpy, w, start, finish, step, NULL, False, True, False); } else { w->opacity = get_opacity_prop(dpy, w, OPAQUE); @@ -1924,7 +1801,7 @@ int compose_main(int argc, char **argv) break; default: if (ev.type == damage_event + XDamageNotify) { - damage_win(dpy, (XDamageNotifyEvent *)&ev); + wComposerProcessDamageEvent(dpy, (XDamageNotifyEvent *)&ev); } else if (ev.type == xshape_event + ShapeNotify) { shape_win(dpy, (XShapeEvent *)&ev); } @@ -1935,7 +1812,7 @@ int compose_main(int argc, char **argv) if (allDamage && !autoRedirect) { static int paint; - paint_all(dpy, allDamage); + wComposerPaintAll(dpy, allDamage); paint++; XSync(dpy, False); allDamage = None; @@ -1943,3 +1820,227 @@ int compose_main(int argc, char **argv) } } } + +//------------------------------------------------------------------------------------------------ +// Composer intialization +//------------------------------------------------------------------------------------------------ + +static Bool wComposerRegister(Display *dpy) +{ + Window w; + Atom a; + static char net_wm_cm[] = "_NET_WM_CM_Sxx"; + + snprintf(net_wm_cm, sizeof(net_wm_cm), "_NET_WM_CM_S%d", scr); + a = XInternAtom(dpy, net_wm_cm, False); + + w = XGetSelectionOwner(dpy, a); + if (w != None) { + XTextProperty tp; + char **strs; + int count; + Atom winNameAtom = XInternAtom(dpy, "_NET_WM_NAME", False); + + if (!XGetTextProperty(dpy, w, &tp, winNameAtom) && !XGetTextProperty(dpy, w, &tp, XA_WM_NAME)) { + fprintf(stderr, "Another composite manager is already running (0x%lx)\n", (unsigned long)w); + return False; + } + if (XmbTextPropertyToTextList(dpy, &tp, &strs, &count) == Success) { + fprintf(stderr, "Another composite manager is already running (%s)\n", strs[0]); + + XFreeStringList(strs); + } + + XFree(tp.value); + + return False; + } + + w = XCreateSimpleWindow(dpy, RootWindow(dpy, scr), 0, 0, 1, 1, 0, None, None); + + Xutf8SetWMProperties(dpy, w, "xcompmgr", "xcompmgr", NULL, 0, NULL, NULL, NULL); + + XSetSelectionOwner(dpy, a, w, 0); + + return True; +} + +static void wComposerAtomsCreate(Display *dpy) +{ + opacityAtom = XInternAtom(dpy, OPACITY_PROP, False); + winTypeAtom = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False); + winDesktopAtom = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DESKTOP", False); + winDockAtom = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DOCK", False); + winToolbarAtom = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_TOOLBAR", False); + winMenuAtom = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_MENU", False); + winUtilAtom = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_UTILITY", False); + winSplashAtom = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_SPLASH", False); + winDialogAtom = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False); + winNormalAtom = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_NORMAL", False); +} + +static Bool wComposerExtensionsCheck(Display *dpy) +{ + // int composite_major, composite_minor; + + if (!XRenderQueryExtension(dpy, &render_event, &render_error)) { + fprintf(stderr, "No render extension\n"); + return False; + } + if (!XQueryExtension(dpy, COMPOSITE_NAME, &composite_opcode, &composite_event, + &composite_error)) { + fprintf(stderr, "No composite extension\n"); + return False; + } + // XCompositeQueryVersion(dpy, &composite_major, &composite_minor); + hasNamePixmap = True; + if (!XDamageQueryExtension(dpy, &damage_event, &damage_error)) { + fprintf(stderr, "No Damage extension\n"); + return False; + } + if (!XFixesQueryExtension(dpy, &xfixes_event, &xfixes_error)) { + fprintf(stderr, "No XFixes extension\n"); + return False; + } + if (!XShapeQueryExtension(dpy, &xshape_event, &xshape_error)) { + fprintf(stderr, "No XShape extension\n"); + return False; + } + + return True; +} + +// int compose_main(int argc, char **argv) +// { + // Specifies the time between steps in a fade in milliseconds. (default 10) + // case 'D': + // fade_delta = atoi(optarg); + // if (fade_delta < 1) { + // fade_delta = 10; + // } + // Specifies the opacity change between steps while fading in. (default 0.028) + // case 'I': + // fade_in_step = atof(optarg); + // if (fade_in_step <= 0) { + // fade_in_step = 0.01; + // } + // Specifies the opacity change between steps while fading out. (default 0.03) + // case 'O': + // fade_out_step = atof(optarg); + // if (fade_out_step <= 0) { + // fade_out_step = 0.01; + // } + // Draw server-side shadows with sharp edges. + // case 's': + // compMode = CompServerShadows; + // Draw client-side shadows with fuzzy edges. + // case 'c': + // compMode = CompClientShadows; + // Avoid drawing shadows on dock/panel windows. + // case 'C': + // excludeDockShadows = True; + // Normal client-side compositing with transparency support + // case 'n': + // compMode = CompSimple; + // Fade windows in/out when opening/closing. + // case 'f': + // fadeWindows = True; + // Fade windows during opacity changes. + // case 'F': + // fadeTrans = True; + // Use automatic server-side compositing. Faster, but no special effects. + // case 'a': + // autoRedirect = True; + // Enable synchronous operation (for debugging). + // case 'S': + // synchronize = True; + // Specifies the blur radius for client-side shadows. (default 12) + // case 'r': + // shadowRadius = atoi(optarg); + // Specifies the translucency for client-side shadows. (default .75) + // case 'o': + // shadowOpacity = atof(optarg); + // Specifies the left offset for client-side shadows. (default -15) + // case 'l': + // shadowOffsetX = atoi(optarg); + // Specifies the top offset for clinet-side shadows. (default -15) + // case 't': + // shadowOffsetY = atoi(optarg); +// } +Bool wComposerInitialize() +{ + // Display *dpy; + char *display = NULL; + Window root_return, parent_return; + Window *children; + unsigned int nchildren; + XRenderPictureAttributes pa; + + // True - CompositeRedirectAutomatic + // False - CompositeRedirectManual + autoRedirect = False; + // CompSimple - looks like a regular X server + // CompServerShadows - use window alpha for shadow; sharp, but precise + // CompClientShadows - use window extents for shadow, blurred + compMode = CompSimple; + + dpy = XOpenDisplay(display); + if (!dpy) { + fprintf(stderr, "Can't open display\n"); + return False; + } + + XSetErrorHandler(wComposerErrorHandler); + + if (synchronize) { + XSynchronize(dpy, 1); + } + scr = DefaultScreen(dpy); + root = RootWindow(dpy, scr); + + if (wComposerExtensionsCheck(dpy) == False) { + return False; + } + + if (wComposerRegister(dpy) == False) { + return False; + } + + wComposerAtomsCreate(dpy); + + pa.subwindow_mode = IncludeInferiors; + + if (compMode == CompClientShadows) { + gaussianMap = make_gaussian_map(dpy, shadowRadius); + presum_gaussian(gaussianMap); + } + + root_width = DisplayWidth(dpy, scr); + root_height = DisplayHeight(dpy, scr); + + rootPicture = XRenderCreatePicture( + dpy, root, XRenderFindVisualFormat(dpy, DefaultVisual(dpy, scr)), CPSubwindowMode, &pa); + blackPicture = wComposerCreateSolidPicture(dpy, True, 1, 0, 0, 0); + if (compMode == CompServerShadows) { + transBlackPicture = wComposerCreateSolidPicture(dpy, True, 0.3, 0, 0, 0); + } + allDamage = None; + clipChanged = True; + + XGrabServer(dpy); + if (autoRedirect) { + XCompositeRedirectSubwindows(dpy, root, CompositeRedirectAutomatic); + } else { + XCompositeRedirectSubwindows(dpy, root, CompositeRedirectManual); + XSelectInput(dpy, root, + SubstructureNotifyMask | ExposureMask | StructureNotifyMask | PropertyChangeMask); + XShapeSelectInput(dpy, root, ShapeNotifyMask); + XQueryTree(dpy, root, &root_return, &parent_return, &children, &nchildren); + for (unsigned int i = 0; i < nchildren; i++) + wComposerAddWindow(dpy, children[i], i ? children[i - 1] : None); + XFree(children); + } + XUngrabServer(dpy); + + return True; +} From e04606750aaf6addbc493c34dcc0a8b85052f9f0 Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Thu, 12 Oct 2023 18:20:53 +0300 Subject: [PATCH 06/67] added necessary dependecies to adopt compositor addition. --- Applications/nextspace-applications.spec | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Applications/nextspace-applications.spec b/Applications/nextspace-applications.spec index bd4fb41fe..686d0efe5 100644 --- a/Applications/nextspace-applications.spec +++ b/Applications/nextspace-applications.spec @@ -24,6 +24,7 @@ BuildRequires: nextspace-frameworks-devel BuildRequires: pam-devel # Workspace BuildRequires: libcorefoundation-devel +BuildRequires: fontconfig-devel BuildRequires: giflib-devel BuildRequires: libjpeg-turbo-devel BuildRequires: libpng-devel @@ -34,7 +35,9 @@ BuildRequires: libXpm-devel BuildRequires: libXmu-devel BuildRequires: libexif-devel BuildRequires: libXfixes-devel -BuildRequires: fontconfig-devel +BuildRequires: libXcomposite-devel +BuildRequires: libXrender-devel +BuildRequires: libXdamage-devel # Requires: nextspace-frameworks Requires: libcorefoundation @@ -44,6 +47,9 @@ Requires: libXinerama Requires: libXpm Requires: libXmu Requires: libXfixes +Requires: libXcomposite +Requires: libXrender +Requires: libXdamage Requires: libexif Requires: xorg-x11-drv-evdev Requires: xorg-x11-drv-intel From 47b7012eec16d954ac91b8b1d24a63f9bd6a3b0a Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Thu, 12 Oct 2023 18:22:29 +0300 Subject: [PATCH 07/67] forward errors to Composer error handler. Handler returns True if error has been processed. --- Applications/Workspace/WM/startup.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Applications/Workspace/WM/startup.c b/Applications/Workspace/WM/startup.c index c88b15fa3..9d0bc50e0 100644 --- a/Applications/Workspace/WM/startup.c +++ b/Applications/Workspace/WM/startup.c @@ -80,6 +80,7 @@ #include "xmodifier.h" #include "dock.h" #include "application.h" +#include "wmcomposer.h" /****** Global ******/ Display *dpy; @@ -175,7 +176,10 @@ static int _catchXError(Display *dpy, XErrorEvent *error) */ || (error->request_code == X_InstallColormap))) { return 0; + } else if (wComposerErrorHandler(dpy, error)) { + return 0; } + FormatXError(dpy, error, buffer, MAXLINE); WMLogWarning(_("internal X error: %s"), buffer); return -1; From 6f088d767b4c745a1258d4c24ed53cae08f1dc75 Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Thu, 12 Oct 2023 18:23:55 +0300 Subject: [PATCH 08/67] start Composer in separated thread before Window Manager. --- Applications/Workspace/Workspace_main.m | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Applications/Workspace/Workspace_main.m b/Applications/Workspace/Workspace_main.m index 01a2f583a..2af6ad283 100644 --- a/Applications/Workspace/Workspace_main.m +++ b/Applications/Workspace/Workspace_main.m @@ -28,6 +28,8 @@ #import "Recycler.h" #import "Workspace+WM.h" +#include "WM/wmcomposer.h" + // Global - set in WM/event.c - WMRunLoop() CFRunLoopRef wm_runloop = NULL; @@ -137,6 +139,22 @@ int main(int argc, const char **argv) fprintf(stderr, "=== Starting Workspace ===\n"); workspace_q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0); + //--- Compositor thread queue ------------------------------------- + { + dispatch_queue_t cmp_q; + cmp_q = dispatch_queue_create("ns.workspace.composer", DISPATCH_QUEUE_CONCURRENT); + dispatch_async(cmp_q, ^{ + fprintf(stderr, "=== Initializing Composer ===\n"); + if (wComposerInitialize() == True) { + fprintf(stderr, "=== Composer initialized ===\n"); + wComposerRunLoop(); + fprintf(stderr, "=== Composer completed it's execution ===\n"); + } else { + fprintf(stderr, "=== Failed to initialize Composer ===\n"); + } + }); + } + //--- Window Manager thread queue ------------------------------------- { dispatch_queue_t wm_q; From db5237c7fe584a39f78e42ccf095d9ba7350c487 Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Thu, 12 Oct 2023 18:24:33 +0300 Subject: [PATCH 09/67] cleanup in log messages. --- Applications/Workspace/WM/event.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Applications/Workspace/WM/event.c b/Applications/Workspace/WM/event.c index 5089618c3..220a1f12a 100644 --- a/Applications/Workspace/WM/event.c +++ b/Applications/Workspace/WM/event.c @@ -318,7 +318,7 @@ void WMRunLoop_V0() { XEvent event; - WMLogError("WMRunLoop0: handling events while run loop is warming up."); + WMLogError("WMRunLoop_V0: handling events while run loop is warming up."); while (wm_runloop == NULL) { WMNextEvent(dpy, &event); WMHandleEvent(&event); @@ -344,7 +344,7 @@ void WMRunLoop_V1() CFFileDescriptorRef xfd; CFRunLoopSourceRef xfd_source; - WMLogError("V1: Entering WM runloop with X connection: %i", ConnectionNumber(dpy)); + WMLogError("WMRunLoop_V1: Entering WM runloop with X connection: %i", ConnectionNumber(dpy)); // X connection file descriptor xfd = CFFileDescriptorCreate(kCFAllocatorDefault, ConnectionNumber(dpy), true, @@ -356,7 +356,7 @@ void WMRunLoop_V1() CFRelease(xfd_source); CFRelease(xfd); - WMLogError("V1: Going into CFRunLoop..."); + WMLogError("WMRunLoop_V1: Going into CFRunLoop..."); wm_runloop = run_loop; CFRunLoopRun(); From b0d17226e0fa9cf8c8944b755b0acdfc9a3e5ce2 Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Fri, 13 Oct 2023 02:12:53 +0300 Subject: [PATCH 10/67] add missed header file and various code cleanup in composer --- Applications/Workspace/WM/wmcomposer.c | 976 +++++++++++++------------ Applications/Workspace/WM/wmcomposer.h | 5 + 2 files changed, 494 insertions(+), 487 deletions(-) create mode 100644 Applications/Workspace/WM/wmcomposer.h diff --git a/Applications/Workspace/WM/wmcomposer.c b/Applications/Workspace/WM/wmcomposer.c index 6bb8804f2..2a4ed83c7 100644 --- a/Applications/Workspace/WM/wmcomposer.c +++ b/Applications/Workspace/WM/wmcomposer.c @@ -44,7 +44,7 @@ typedef struct _ignore { struct _ignore *next; unsigned long sequence; -} ignore; +} CMPIgnoreSequence; typedef struct _win { struct _win *next; @@ -73,7 +73,7 @@ typedef struct _win { /* for drawing translucent windows */ XserverRegion borderClip; struct _win *prev_trans; -} win; +} CMPWindow; typedef struct _conv { int size; @@ -82,18 +82,18 @@ typedef struct _conv { typedef struct _fade { struct _fade *next; - win *w; + Display *dpy; + CMPWindow *w; double cur; double finish; double step; - void (*callback)(Display *dpy, win *w, Bool gone); - Display *dpy; + void (*callback)(Display *dpy, CMPWindow *w, Bool gone); Bool gone; -} fade; +} CMPFade; static Display *dpy; -static win *list; -static fade *fades; +static CMPWindow *list; +static CMPFade *fades; static int scr; static Window root; static Picture rootPicture; @@ -105,7 +105,7 @@ static XserverRegion allDamage; static Bool clipChanged; static Bool hasNamePixmap; static int root_height, root_width; -static ignore *ignore_head, **ignore_tail = &ignore_head; +static CMPIgnoreSequence *ignore_head, **ignore_tail = &ignore_head; static int xfixes_event, xfixes_error; static int damage_event, damage_error; static int composite_event, composite_error; @@ -144,13 +144,18 @@ typedef enum _compMode { CompClientShadows, /* use window extents for shadow, blurred */ } CompMode; -static void determine_mode(Display *dpy, win *w); +static void determine_mode(Display *dpy, CMPWindow *w); -static double get_opacity_percent(Display *dpy, win *w, double def); +static double get_window_opacity_value(Display *dpy, CMPWindow *w, double def); -static unsigned int get_opacity_prop(Display *dpy, win *w, unsigned int def); +static unsigned int get_window_opacity_property(Display *dpy, CMPWindow *w, unsigned int def); -static XserverRegion win_extents(Display *dpy, win *w); +static XserverRegion window_extents_region(Display *dpy, CMPWindow *w); +static XserverRegion window_border_size(Display *dpy, CMPWindow *w); + +static void wComposerDiscardEventIgnore(Display *dpy, unsigned long sequence); +static void wComposerSetEventIgnore(Display *dpy, unsigned long sequence); +static int wComposerShouldIgnoreEvent(Display *dpy, unsigned long sequence); static CompMode compMode = CompSimple; @@ -185,9 +190,9 @@ static int get_time_in_milliseconds(void) // Fading // ---------------------------------------------------------------------------------------------- -static fade *find_fade(win *w) +static CMPFade *find_fade(CMPWindow *w) { - fade *f; + CMPFade *f; for (f = fades; f; f = f->next) { if (f->w == w) { @@ -197,9 +202,9 @@ static fade *find_fade(win *w) return NULL; } -static void dequeue_fade(Display *dpy, fade *f) +static void dequeue_fade(Display *dpy, CMPFade *f) { - fade **prev; + CMPFade **prev; for (prev = &fades; *prev; prev = &(*prev)->next) if (*prev == f) { @@ -212,15 +217,15 @@ static void dequeue_fade(Display *dpy, fade *f) } } -static void cleanup_fade(Display *dpy, win *w) +static void cleanup_fade(Display *dpy, CMPWindow *w) { - fade *f = find_fade(w); + CMPFade *f = find_fade(w); if (f) { dequeue_fade(dpy, f); } } -static void enqueue_fade(Display *dpy, fade *f) +static void enqueue_fade(Display *dpy, CMPFade *f) { if (!fades) { fade_time = get_time_in_milliseconds() + fade_delta; @@ -229,15 +234,15 @@ static void enqueue_fade(Display *dpy, fade *f) fades = f; } -static void set_fade(Display *dpy, win *w, double start, double finish, double step, - void (*callback)(Display *dpy, win *w, Bool gone), Bool gone, +static void set_fade(Display *dpy, CMPWindow *w, double start, double finish, double step, + void (*callback)(Display *dpy, CMPWindow *w, Bool gone), Bool gone, Bool exec_callback, Bool override) { - fade *f; + CMPFade *f; f = find_fade(w); if (!f) { - f = malloc(sizeof(fade)); + f = malloc(sizeof(CMPFade)); f->next = NULL; f->w = w; f->cur = start; @@ -271,7 +276,7 @@ static void set_fade(Display *dpy, win *w, double start, double finish, double s if (w->shadow) { XRenderFreePicture(dpy, w->shadow); w->shadow = None; - w->extents = win_extents(dpy, w); + w->extents = window_extents_region(dpy, w); } } @@ -293,7 +298,7 @@ static int fade_timeout(void) static void run_fades(Display *dpy) { int now = get_time_in_milliseconds(); - fade *next = fades; + CMPFade *next = fades; int steps; Bool need_dequeue; @@ -302,8 +307,8 @@ static void run_fades(Display *dpy) steps = 1 + (now - fade_time) / fade_delta; while (next) { - fade *f = next; - win *w = f->w; + CMPFade *f = next; + CMPWindow *w = f->w; next = f->next; f->cur += f->step * steps; if (f->cur >= 1) { @@ -328,7 +333,7 @@ static void run_fades(Display *dpy) if (w->shadow) { XRenderFreePicture(dpy, w->shadow); w->shadow = None; - w->extents = win_extents(dpy, w); + w->extents = window_extents_region(dpy, w); } /* Must do this last as it might destroy f->w in callbacks */ if (need_dequeue) { @@ -339,7 +344,7 @@ static void run_fades(Display *dpy) } // ---------------------------------------------------------------------------------------------- -// Gaussian utilities +// Gaussian blur // ---------------------------------------------------------------------------------------------- static double gaussian(double r, double x, double y) { @@ -485,9 +490,9 @@ static void presum_gaussian(conv *map) } // ---------------------------------------------------------------------------------------------- -// Shadows +// Pictures and images // ---------------------------------------------------------------------------------------------- -static XImage *make_shadow(Display *dpy, double opacity, int width, int height) +static XImage *create_shadow_image(Display *dpy, double opacity, int width, int height) { XImage *ximage; unsigned char *data; @@ -582,15 +587,15 @@ static XImage *make_shadow(Display *dpy, double opacity, int width, int height) return ximage; } -static Picture shadow_picture(Display *dpy, double opacity, Picture alpha_pict, int width, - int height, int *wp, int *hp) +static Picture create_shadow_picture(Display *dpy, double opacity, Picture alpha_pict, + int width, int height, int *wp, int *hp) { XImage *shadowImage; Pixmap shadowPixmap; Picture shadowPicture; GC gc; - shadowImage = make_shadow(dpy, opacity, width, height); + shadowImage = create_shadow_image(dpy, opacity, width, height); if (!shadowImage) { return None; } @@ -626,8 +631,7 @@ static Picture shadow_picture(Display *dpy, double opacity, Picture alpha_pict, return shadowPicture; } - -static Picture wComposerCreateSolidPicture(Display *dpy, Bool argb, double a, double r, double g, double b) +static Picture create_solid_picture(Display *dpy, Bool argb, double a, double r, double g, double b) { Pixmap pixmap; Picture picture; @@ -654,59 +658,10 @@ static Picture wComposerCreateSolidPicture(Display *dpy, Bool argb, double a, do c.blue = b * 0xffff; XRenderFillRectangle(dpy, PictOpSrc, picture, &c, 0, 0, 1, 1); XFreePixmap(dpy, pixmap); - return picture; -} - -// ---------------------------------------------------------------------------------------------- -// Events -// ---------------------------------------------------------------------------------------------- -static void discard_ignore(Display *dpy, unsigned long sequence) -{ - while (ignore_head) { - if ((long)(sequence - ignore_head->sequence) > 0) { - ignore *next = ignore_head->next; - free(ignore_head); - ignore_head = next; - if (!ignore_head) { - ignore_tail = &ignore_head; - } - } else { - break; - } - } -} - -static void set_ignore(Display *dpy, unsigned long sequence) -{ - ignore *i = malloc(sizeof(ignore)); - if (!i) { - return; - } - - i->sequence = sequence; - i->next = NULL; - *ignore_tail = i; - ignore_tail = &i->next; -} - -static int should_ignore(Display *dpy, unsigned long sequence) -{ - discard_ignore(dpy, sequence); - return ignore_head && ignore_head->sequence == sequence; + return picture; } -static win *find_win(Display *dpy, Window id) -{ - win *w; - - for (w = list; w; w = w->next) { - if (w->id == id) { - return w; - } - } - return NULL; -} static const char *backgroundProps[] = { "_XROOTPMAP_ID", @@ -714,7 +669,7 @@ static const char *backgroundProps[] = { NULL, }; -static Picture root_tile(Display *dpy) +static Picture root_tile_picture(Display *dpy) { Picture picture; Atom actual_type; @@ -757,91 +712,20 @@ static Picture root_tile(Display *dpy) return picture; } -static void paint_root(Display *dpy) +static void paint_root_window(Display *dpy) { if (!rootTile) { - rootTile = root_tile(dpy); + rootTile = root_tile_picture(dpy); } XRenderComposite(dpy, PictOpSrc, rootTile, None, rootBuffer, 0, 0, 0, 0, 0, 0, root_width, root_height); } -static XserverRegion win_extents(Display *dpy, win *w) -{ - XRectangle r; - - r.x = w->a.x; - r.y = w->a.y; - r.width = w->a.width + w->a.border_width * 2; - r.height = w->a.height + w->a.border_width * 2; - if (compMode != CompSimple && !(w->windowType == winDockAtom && excludeDockShadows)) { - if (compMode == CompServerShadows || w->mode != WINDOW_ARGB) { - XRectangle sr; - - if (compMode == CompServerShadows) { - w->shadow_dx = 2; - w->shadow_dy = 7; - w->shadow_width = w->a.width; - w->shadow_height = w->a.height; - } else { - w->shadow_dx = shadowOffsetX; - w->shadow_dy = shadowOffsetY; - if (!w->shadow) { - double opacity = shadowOpacity; - if (w->mode == WINDOW_TRANS) { - opacity = opacity * ((double)w->opacity) / ((double)OPAQUE); - } - w->shadow = shadow_picture(dpy, opacity, w->alphaPict, w->a.width + w->a.border_width * 2, - w->a.height + w->a.border_width * 2, &w->shadow_width, - &w->shadow_height); - } - } - sr.x = w->a.x + w->shadow_dx; - sr.y = w->a.y + w->shadow_dy; - sr.width = w->shadow_width; - sr.height = w->shadow_height; - if (sr.x < r.x) { - r.width = (r.x + r.width) - sr.x; - r.x = sr.x; - } - if (sr.y < r.y) { - r.height = (r.y + r.height) - sr.y; - r.y = sr.y; - } - if (sr.x + sr.width > r.x + r.width) { - r.width = sr.x + sr.width - r.x; - } - if (sr.y + sr.height > r.y + r.height) { - r.height = sr.y + sr.height - r.y; - } - } - } - return XFixesCreateRegion(dpy, &r, 1); -} - -static XserverRegion border_size(Display *dpy, win *w) -{ - XserverRegion border; - /* - * if window doesn't exist anymore, this will generate an error - * as well as not generate a region. Perhaps a better XFixes - * architecture would be to have a request that copies instead - * of creates, that way you'd just end up with an empty region - * instead of an invalid XID. - */ - set_ignore(dpy, NextRequest(dpy)); - border = XFixesCreateRegionFromWindow(dpy, w->id, WindowRegionBounding); - /* translate this */ - set_ignore(dpy, NextRequest(dpy)); - XFixesTranslateRegion(dpy, border, w->a.x + w->a.border_width, w->a.y + w->a.border_width); - return border; -} - -static void wComposerPaintAll(Display *dpy, XserverRegion region) +static void paint_all(Display *dpy, XserverRegion region) { - win *w; - win *t = NULL; + CMPWindow *w; + CMPWindow *t = NULL; if (!region) { XRectangle r; @@ -885,7 +769,7 @@ static void wComposerPaintAll(Display *dpy, XserverRegion region) } if (clipChanged) { if (w->borderSize) { - set_ignore(dpy, NextRequest(dpy)); + wComposerSetEventIgnore(dpy, NextRequest(dpy)); XFixesDestroyRegion(dpy, w->borderSize); w->borderSize = None; } @@ -899,10 +783,10 @@ static void wComposerPaintAll(Display *dpy, XserverRegion region) } } if (!w->borderSize) { - w->borderSize = border_size(dpy, w); + w->borderSize = window_border_size(dpy, w); } if (!w->extents) { - w->extents = win_extents(dpy, w); + w->extents = window_extents_region(dpy, w); } if (w->mode == WINDOW_SOLID) { int x, y, wid, hei; @@ -911,9 +795,9 @@ static void wComposerPaintAll(Display *dpy, XserverRegion region) wid = w->a.width + w->a.border_width * 2; hei = w->a.height + w->a.border_width * 2; XFixesSetPictureClipRegion(dpy, rootBuffer, 0, 0, region); - set_ignore(dpy, NextRequest(dpy)); + wComposerSetEventIgnore(dpy, NextRequest(dpy)); XFixesSubtractRegion(dpy, region, region, w->borderSize); - set_ignore(dpy, NextRequest(dpy)); + wComposerSetEventIgnore(dpy, NextRequest(dpy)); XRenderComposite(dpy, PictOpSrc, w->picture, None, rootBuffer, 0, 0, 0, 0, x, y, wid, hei); } if (!w->borderClip) { @@ -924,7 +808,7 @@ static void wComposerPaintAll(Display *dpy, XserverRegion region) t = w; } XFixesSetPictureClipRegion(dpy, rootBuffer, 0, 0, region); - paint_root(dpy); + paint_root_window(dpy); for (w = t; w; w = w->prev_trans) { XFixesSetPictureClipRegion(dpy, rootBuffer, 0, 0, w->borderClip); switch (compMode) { @@ -934,9 +818,9 @@ static void wComposerPaintAll(Display *dpy, XserverRegion region) /* dont' bother drawing shadows on desktop windows */ if (w->windowType == winDesktopAtom) break; - set_ignore(dpy, NextRequest(dpy)); + wComposerSetEventIgnore(dpy, NextRequest(dpy)); if (w->opacity != OPAQUE && !w->shadowPict) - w->shadowPict = wComposerCreateSolidPicture(dpy, True, (double)w->opacity / OPAQUE * 0.3, 0, 0, 0); + w->shadowPict = create_solid_picture(dpy, True, (double)w->opacity / OPAQUE * 0.3, 0, 0, 0); XRenderComposite(dpy, PictOpOver, w->shadowPict ? w->shadowPict : transBlackPicture, w->picture, rootBuffer, 0, 0, 0, 0, w->a.x + w->shadow_dx, w->a.y + w->shadow_dy, w->shadow_width, w->shadow_height); @@ -951,7 +835,7 @@ static void wComposerPaintAll(Display *dpy, XserverRegion region) break; } if (w->opacity != OPAQUE && !w->alphaPict) { - w->alphaPict = wComposerCreateSolidPicture(dpy, False, (double)w->opacity / OPAQUE, 0, 0, 0); + w->alphaPict = create_solid_picture(dpy, False, (double)w->opacity / OPAQUE, 0, 0, 0); } if (w->mode == WINDOW_TRANS) { int x, y, wid, hei; @@ -961,7 +845,7 @@ static void wComposerPaintAll(Display *dpy, XserverRegion region) y = w->a.y; wid = w->a.width + w->a.border_width * 2; hei = w->a.height + w->a.border_width * 2; - set_ignore(dpy, NextRequest(dpy)); + wComposerSetEventIgnore(dpy, NextRequest(dpy)); XRenderComposite(dpy, PictOpOver, w->picture, w->alphaPict, rootBuffer, 0, 0, 0, 0, x, y, wid, hei); } else if (w->mode == WINDOW_ARGB) { @@ -972,7 +856,7 @@ static void wComposerPaintAll(Display *dpy, XserverRegion region) y = w->a.y; wid = w->a.width + w->a.border_width * 2; hei = w->a.height + w->a.border_width * 2; - set_ignore(dpy, NextRequest(dpy)); + wComposerSetEventIgnore(dpy, NextRequest(dpy)); XRenderComposite(dpy, PictOpOver, w->picture, w->alphaPict, rootBuffer, 0, 0, 0, 0, x, y, wid, hei); } @@ -987,7 +871,7 @@ static void wComposerPaintAll(Display *dpy, XserverRegion region) } } -static void add_damage(Display *dpy, XserverRegion damage) +static void add_damage_region(Display *dpy, XserverRegion damage) { if (allDamage) { XFixesUnionRegion(dpy, allDamage, allDamage, damage); @@ -997,17 +881,103 @@ static void add_damage(Display *dpy, XserverRegion damage) } } -static void repair_win(Display *dpy, win *w) +// ---------------------------------------------------------------------------------------------- +// Windows +// ---------------------------------------------------------------------------------------------- +static CMPWindow *find_window(Display *dpy, Window id) +{ + CMPWindow *w; + + for (w = list; w; w = w->next) { + if (w->id == id) { + return w; + } + } + return NULL; +} + +static XserverRegion window_extents_region(Display *dpy, CMPWindow *w) +{ + XRectangle r; + + r.x = w->a.x; + r.y = w->a.y; + r.width = w->a.width + w->a.border_width * 2; + r.height = w->a.height + w->a.border_width * 2; + if (compMode != CompSimple && !(w->windowType == winDockAtom && excludeDockShadows)) { + if (compMode == CompServerShadows || w->mode != WINDOW_ARGB) { + XRectangle sr; + + if (compMode == CompServerShadows) { + w->shadow_dx = 2; + w->shadow_dy = 7; + w->shadow_width = w->a.width; + w->shadow_height = w->a.height; + } else { + w->shadow_dx = shadowOffsetX; + w->shadow_dy = shadowOffsetY; + if (!w->shadow) { + double opacity = shadowOpacity; + if (w->mode == WINDOW_TRANS) { + opacity = opacity * ((double)w->opacity) / ((double)OPAQUE); + } + w->shadow = create_shadow_picture(dpy, opacity, w->alphaPict, w->a.width + w->a.border_width * 2, + w->a.height + w->a.border_width * 2, &w->shadow_width, + &w->shadow_height); + } + } + sr.x = w->a.x + w->shadow_dx; + sr.y = w->a.y + w->shadow_dy; + sr.width = w->shadow_width; + sr.height = w->shadow_height; + if (sr.x < r.x) { + r.width = (r.x + r.width) - sr.x; + r.x = sr.x; + } + if (sr.y < r.y) { + r.height = (r.y + r.height) - sr.y; + r.y = sr.y; + } + if (sr.x + sr.width > r.x + r.width) { + r.width = sr.x + sr.width - r.x; + } + if (sr.y + sr.height > r.y + r.height) { + r.height = sr.y + sr.height - r.y; + } + } + } + return XFixesCreateRegion(dpy, &r, 1); +} + +static XserverRegion window_border_size(Display *dpy, CMPWindow *w) +{ + XserverRegion border; + /* + * if window doesn't exist anymore, this will generate an error + * as well as not generate a region. Perhaps a better XFixes + * architecture would be to have a request that copies instead + * of creates, that way you'd just end up with an empty region + * instead of an invalid XID. + */ + wComposerSetEventIgnore(dpy, NextRequest(dpy)); + border = XFixesCreateRegionFromWindow(dpy, w->id, WindowRegionBounding); + /* translate this */ + wComposerSetEventIgnore(dpy, NextRequest(dpy)); + XFixesTranslateRegion(dpy, border, w->a.x + w->a.border_width, w->a.y + w->a.border_width); + return border; +} + +static void repair_window(Display *dpy, CMPWindow *w) { XserverRegion parts; if (!w->damaged) { - parts = win_extents(dpy, w); - set_ignore(dpy, NextRequest(dpy)); + parts = window_extents_region(dpy, w); + wComposerSetEventIgnore(dpy, NextRequest(dpy)); XDamageSubtract(dpy, w->damage, None, None); } else { parts = XFixesCreateRegion(dpy, NULL, 0); - set_ignore(dpy, NextRequest(dpy)); + wComposerSetEventIgnore(dpy, NextRequest(dpy)); XDamageSubtract(dpy, w->damage, None, parts); XFixesTranslateRegion(dpy, parts, w->a.x + w->a.border_width, w->a.y + w->a.border_width); if (compMode == CompServerShadows) { @@ -1018,13 +988,13 @@ static void repair_win(Display *dpy, win *w) XFixesDestroyRegion(dpy, o); } } - add_damage(dpy, parts); + add_damage_region(dpy, parts); w->damaged = 1; } -static void wComposerMapWindow(Display *dpy, Window id, unsigned long sequence, Bool doFade) +static void map_window(Display *dpy, Window id, unsigned long sequence, Bool doFade) { - win *w = find_win(dpy, id); + CMPWindow *w = find_window(dpy, id); if (!w) { return; @@ -1035,21 +1005,21 @@ static void wComposerMapWindow(Display *dpy, Window id, unsigned long sequence, XSelectInput(dpy, id, PropertyChangeMask); /* This needs to be here since we don't get PropertyNotify when unmapped */ - w->opacity = get_opacity_prop(dpy, w, OPAQUE); + w->opacity = get_window_opacity_property(dpy, w, OPAQUE); determine_mode(dpy, w); w->damaged = 0; if (doFade && fadeWindows) { - set_fade(dpy, w, 0, get_opacity_percent(dpy, w, 1.0), fade_in_step, NULL, False, True, True); + set_fade(dpy, w, 0, get_window_opacity_value(dpy, w, 1.0), fade_in_step, NULL, False, True, True); } } -static void finish_unmap_win(Display *dpy, win *w) +static void finish_unmap_window(Display *dpy, CMPWindow *w) { w->damaged = 0; if (w->extents != None) { - add_damage(dpy, w->extents); /* destroys region */ + add_damage_region(dpy, w->extents); /* destroys region */ w->extents = None; } @@ -1059,17 +1029,17 @@ static void finish_unmap_win(Display *dpy, win *w) } if (w->picture) { - set_ignore(dpy, NextRequest(dpy)); + wComposerSetEventIgnore(dpy, NextRequest(dpy)); XRenderFreePicture(dpy, w->picture); w->picture = None; } /* don't care about properties anymore */ - set_ignore(dpy, NextRequest(dpy)); + wComposerSetEventIgnore(dpy, NextRequest(dpy)); XSelectInput(dpy, w->id, 0); if (w->borderSize) { - set_ignore(dpy, NextRequest(dpy)); + wComposerSetEventIgnore(dpy, NextRequest(dpy)); XFixesDestroyRegion(dpy, w->borderSize); w->borderSize = None; } @@ -1085,20 +1055,22 @@ static void finish_unmap_win(Display *dpy, win *w) clipChanged = True; } -static void unmap_callback(Display *dpy, win *w, Bool gone) { finish_unmap_win(dpy, w); } - -static void wComposerUnmapWindow(Display *dpy, Window id, Bool doFade) +static void unmap_window_callback(Display *dpy, CMPWindow *w, Bool gone) +{ + finish_unmap_window(dpy, w); +} +static void unmap_window(Display *dpy, Window id, Bool doFade) { - win *w = find_win(dpy, id); + CMPWindow *w = find_window(dpy, id); if (!w) { return; } w->a.map_state = IsUnmapped; if (w->pixmap && doFade && fadeWindows) { - set_fade(dpy, w, w->opacity * 1.0 / OPAQUE, 0.0, fade_out_step, unmap_callback, False, False, + set_fade(dpy, w, w->opacity * 1.0 / OPAQUE, 0.0, fade_out_step, unmap_window_callback, False, False, True); } else { - finish_unmap_win(dpy, w); + finish_unmap_window(dpy, w); } } @@ -1106,7 +1078,7 @@ static void wComposerUnmapWindow(Display *dpy, Window id, Bool doFade) not found: default otherwise the value */ -static unsigned int get_opacity_prop(Display *dpy, win *w, unsigned int def) +static unsigned int get_window_opacity_property(Display *dpy, CMPWindow *w, unsigned int def) { Atom actual; int format; @@ -1128,9 +1100,9 @@ static unsigned int get_opacity_prop(Display *dpy, win *w, unsigned int def) not found: default otherwise: the value */ -static double get_opacity_percent(Display *dpy, win *w, double def) +static double get_window_opacity_value(Display *dpy, CMPWindow *w, double def) { - unsigned int opacity = get_opacity_prop(dpy, w, (unsigned int)(OPAQUE * def)); + unsigned int opacity = get_window_opacity_property(dpy, w, (unsigned int)(OPAQUE * def)); return opacity * 1.0 / OPAQUE; } @@ -1139,7 +1111,7 @@ static double get_opacity_percent(Display *dpy, win *w, double def) Future might check for menu flag and other cool things */ -static Atom get_wintype_prop(Display *dpy, Window w) +static Atom get_window_type_property(Display *dpy, Window w) { Atom actual; int format; @@ -1158,7 +1130,7 @@ static Atom get_wintype_prop(Display *dpy, Window w) return winNormalAtom; } -static void determine_mode(Display *dpy, win *w) +static void determine_mode(Display *dpy, CMPWindow *w) { int mode; XRenderPictFormat *format; @@ -1192,18 +1164,18 @@ static void determine_mode(Display *dpy, win *w) XserverRegion damage; damage = XFixesCreateRegion(dpy, NULL, 0); XFixesCopyRegion(dpy, damage, w->extents); - add_damage(dpy, damage); + add_damage_region(dpy, damage); } } -static Atom determine_wintype(Display *dpy, Window w) +static Atom get_window_type(Display *dpy, Window w) { Window root_return, parent_return; Window *children = NULL; unsigned int nchildren; Atom type; - type = get_wintype_prop(dpy, w); + type = get_window_type_property(dpy, w); if (type != winNormalAtom) return type; @@ -1216,7 +1188,7 @@ static Atom determine_wintype(Display *dpy, Window w) } for (unsigned int i = 0; i < nchildren; i++) { - type = determine_wintype(dpy, children[i]); + type = get_window_type(dpy, children[i]); if (type != winNormalAtom) { return type; } @@ -1228,10 +1200,10 @@ static Atom determine_wintype(Display *dpy, Window w) return winNormalAtom; } -static void wComposerAddWindow(Display *dpy, Window id, Window prev) +static void add_window(Display *dpy, Window id, Window prev) { - win *new = malloc(sizeof(win)); - win **p; + CMPWindow *new = malloc(sizeof(CMPWindow)); + CMPWindow **p; if (!new) return; @@ -1245,7 +1217,7 @@ static void wComposerAddWindow(Display *dpy, Window id, Window prev) p = &list; } new->id = id; - set_ignore(dpy, NextRequest(dpy)); + wComposerSetEventIgnore(dpy, NextRequest(dpy)); if (!XGetWindowAttributes(dpy, id, &new->a)) { free(new); return; @@ -1280,16 +1252,16 @@ static void wComposerAddWindow(Display *dpy, Window id, Window prev) new->borderClip = None; new->prev_trans = NULL; - new->windowType = determine_wintype(dpy, new->id); + new->windowType = get_window_type(dpy, new->id); new->next = *p; *p = new; if (new->a.map_state == IsViewable) { - wComposerMapWindow(dpy, id, new->damage_sequence - 1, True); + map_window(dpy, id, new->damage_sequence - 1, True); } } -static void restack_win(Display *dpy, win *w, Window new_above) +static void restack_window(Display *dpy, CMPWindow *w, Window new_above) { Window old_above; @@ -1299,7 +1271,7 @@ static void restack_win(Display *dpy, win *w, Window new_above) old_above = None; } if (old_above != new_above) { - win **prev; + CMPWindow **prev; /* unhook */ for (prev = &list; *prev; prev = &(*prev)->next) { @@ -1320,9 +1292,9 @@ static void restack_win(Display *dpy, win *w, Window new_above) } } -static void wComposerConfigureWindow(Display *dpy, XConfigureEvent *ce) +static void configure_window(Display *dpy, XConfigureEvent *ce) { - win *w = find_win(dpy, ce->window); + CMPWindow *w = find_window(dpy, ce->window); XserverRegion damage = None; if (!w) { @@ -1362,12 +1334,12 @@ static void wComposerConfigureWindow(Display *dpy, XConfigureEvent *ce) w->a.height = ce->height; w->a.border_width = ce->border_width; w->a.override_redirect = ce->override_redirect; - restack_win(dpy, w, ce->above); + restack_window(dpy, w, ce->above); if (damage) { - XserverRegion extents = win_extents(dpy, w); + XserverRegion extents = window_extents_region(dpy, w); XFixesUnionRegion(dpy, damage, damage, extents); XFixesDestroyRegion(dpy, extents); - add_damage(dpy, damage); + add_damage_region(dpy, damage); } w->shape_bounds.x += w->a.x; w->shape_bounds.y += w->a.y; @@ -1379,9 +1351,9 @@ static void wComposerConfigureWindow(Display *dpy, XConfigureEvent *ce) clipChanged = True; } -static void circulate_win(Display *dpy, XCirculateEvent *ce) +static void circulate_windows(Display *dpy, XCirculateEvent *ce) { - win *w = find_win(dpy, ce->window); + CMPWindow *w = find_window(dpy, ce->window); Window new_above; if (!w) { @@ -1392,22 +1364,22 @@ static void circulate_win(Display *dpy, XCirculateEvent *ce) } else { new_above = None; } - restack_win(dpy, w, new_above); + restack_window(dpy, w, new_above); clipChanged = True; } -static void finish_destroy_win(Display *dpy, Window id, Bool gone) +static void finish_destroy_window(Display *dpy, Window id, Bool gone) { - win **prev, *w; + CMPWindow **prev, *w; for (prev = &list; (w = *prev); prev = &w->next) { if (w->id == id) { if (gone) { - finish_unmap_win(dpy, w); + finish_unmap_window(dpy, w); } *prev = w->next; if (w->picture) { - set_ignore(dpy, NextRequest(dpy)); + wComposerSetEventIgnore(dpy, NextRequest(dpy)); XRenderFreePicture(dpy, w->picture); w->picture = None; } @@ -1424,7 +1396,7 @@ static void finish_destroy_win(Display *dpy, Window id, Bool gone) w->shadow = None; } if (w->damage != None) { - set_ignore(dpy, NextRequest(dpy)); + wComposerSetEventIgnore(dpy, NextRequest(dpy)); XDamageDestroy(dpy, w->damage); w->damage = None; } @@ -1435,75 +1407,59 @@ static void finish_destroy_win(Display *dpy, Window id, Bool gone) } } -static void destroy_callback(Display *dpy, win *w, Bool gone) +static void destroy_callback(Display *dpy, CMPWindow *w, Bool gone) { - finish_destroy_win(dpy, w->id, gone); + finish_destroy_window(dpy, w->id, gone); } -static void wComposerRemoveWindow(Display *dpy, Window id, Bool gone, Bool doFade) +static void destroy_window(Display *dpy, Window id, Bool gone, Bool doFade) { - win *w = find_win(dpy, id); + CMPWindow *w = find_window(dpy, id); if (w && w->pixmap && doFade && fadeWindows) { set_fade(dpy, w, w->opacity * 1.0 / OPAQUE, 0.0, fade_out_step, destroy_callback, gone, False, True); } else { - finish_destroy_win(dpy, id, gone); + finish_destroy_window(dpy, id, gone); } } -static void wComposerProcessDamageEvent(Display *dpy, XDamageNotifyEvent *de) +// ---------------------------------------------------------------------------------------------- +// Events +// ---------------------------------------------------------------------------------------------- +static void wComposerDiscardEventIgnore(Display *dpy, unsigned long sequence) { - win *w = find_win(dpy, de->drawable); - - if (!w) { - return; + while (ignore_head) { + if ((long)(sequence - ignore_head->sequence) > 0) { + CMPIgnoreSequence *next = ignore_head->next; + free(ignore_head); + ignore_head = next; + if (!ignore_head) { + ignore_tail = &ignore_head; + } + } else { + break; + } } - repair_win(dpy, w); } -static void shape_win(Display *dpy, XShapeEvent *se) +static void wComposerSetEventIgnore(Display *dpy, unsigned long sequence) { - win *w = find_win(dpy, se->window); + CMPIgnoreSequence *i = malloc(sizeof(CMPIgnoreSequence)); - if (!w) { + if (!i) { return; } - if (se->kind == ShapeClip || se->kind == ShapeBounding) { - XserverRegion region0; - XserverRegion region1; - - clipChanged = True; - - region0 = XFixesCreateRegion(dpy, &w->shape_bounds, 1); - - if (se->shaped == True) { - w->shaped = True; - w->shape_bounds.x = w->a.x + se->x; - w->shape_bounds.y = w->a.y + se->y; - w->shape_bounds.width = se->width; - w->shape_bounds.height = se->height; - } else { - w->shaped = False; - w->shape_bounds.x = w->a.x; - w->shape_bounds.y = w->a.y; - w->shape_bounds.width = w->a.width; - w->shape_bounds.height = w->a.height; - } - - region1 = XFixesCreateRegion(dpy, &w->shape_bounds, 1); - XFixesUnionRegion(dpy, region0, region0, region1); - XFixesDestroyRegion(dpy, region1); - - /* ask for repaint of the old and new region */ - wComposerPaintAll(dpy, region0); - } + + i->sequence = sequence; + i->next = NULL; + *ignore_tail = i; + ignore_tail = &i->next; } -static void expose_root(Display *dpy, Window rootwin, XRectangle *rects, int nrects) +static int wComposerShouldIgnoreEvent(Display *dpy, unsigned long sequence) { - XserverRegion region = XFixesCreateRegion(dpy, rects, nrects); - - add_damage(dpy, region); + wComposerDiscardEventIgnore(dpy, sequence); + return ignore_head && ignore_head->sequence == sequence; } Bool wComposerErrorHandler(Display *dpy, XErrorEvent *ev) @@ -1512,7 +1468,7 @@ Bool wComposerErrorHandler(Display *dpy, XErrorEvent *ev) const char *name = NULL; static char buffer[256]; - if (should_ignore(dpy, ev->serial)) { + if (wComposerShouldIgnoreEvent(dpy, ev->serial)) { return True; } @@ -1572,128 +1528,174 @@ Bool wComposerErrorHandler(Display *dpy, XErrorEvent *ev) return True; } -// static XRectangle *expose_rects = NULL; -// static int size_expose = 0; -// static int n_expose = 0; -// static int p; -// void wComposerProcessEvent(Display *dpy, XEvent ev) -// { -// if (!autoRedirect) { -// switch (ev.type) { -// case CreateNotify: -// wComposerAddWindow(dpy, ev.xcreatewindow.window, 0); -// break; -// case ConfigureNotify: -// wComposerConfigureWindow(dpy, &ev.xconfigure); -// break; -// case DestroyNotify: -// wComposerRemoveWindow(dpy, ev.xdestroywindow.window, True, True); -// break; -// case MapNotify: -// wComposerMapWindow(dpy, ev.xmap.window, ev.xmap.serial, True); -// break; -// case UnmapNotify: -// wComposerUnmapWindow(dpy, ev.xunmap.window, True); -// break; -// case ReparentNotify: -// if (ev.xreparent.parent == root) { -// wComposerAddWindow(dpy, ev.xreparent.window, 0); -// } else { -// wComposerRemoveWindow(dpy, ev.xreparent.window, False, True); -// } -// break; -// case CirculateNotify: -// circulate_win(dpy, &ev.xcirculate); -// break; -// case Expose: -// if (ev.xexpose.window == root) { -// int more = ev.xexpose.count + 1; -// if (n_expose == size_expose) { -// if (expose_rects) { -// expose_rects = realloc(expose_rects, (size_expose + more) * sizeof(XRectangle)); -// size_expose += more; -// } else { -// expose_rects = malloc(more * sizeof(XRectangle)); -// size_expose = more; -// } -// } -// expose_rects[n_expose].x = ev.xexpose.x; -// expose_rects[n_expose].y = ev.xexpose.y; -// expose_rects[n_expose].width = ev.xexpose.width; -// expose_rects[n_expose].height = ev.xexpose.height; -// n_expose++; -// if (ev.xexpose.count == 0) { -// expose_root(dpy, root, expose_rects, n_expose); -// n_expose = 0; -// } -// } -// break; -// case PropertyNotify: -// for (p = 0; backgroundProps[p]; p++) { -// if (ev.xproperty.atom == XInternAtom(dpy, backgroundProps[p], False)) { -// if (rootTile) { -// XClearArea(dpy, root, 0, 0, 0, 0, True); -// XRenderFreePicture(dpy, rootTile); -// rootTile = None; -// break; -// } -// } -// } -// /* check if Trans property was changed */ -// if (ev.xproperty.atom == opacityAtom) { -// /* reset mode and redraw window */ -// win *w = find_win(dpy, ev.xproperty.window); -// if (w) { -// if (fadeTrans) { -// double start, finish, step; -// start = w->opacity * 1.0 / OPAQUE; -// finish = get_opacity_percent(dpy, w, 1.0); -// if (start > finish) -// step = fade_in_step; -// else -// step = fade_out_step; -// set_fade(dpy, w, start, finish, step, NULL, False, True, False); -// } else { -// w->opacity = get_opacity_prop(dpy, w, OPAQUE); -// determine_mode(dpy, w); -// if (w->shadow) { -// XRenderFreePicture(dpy, w->shadow); -// w->shadow = None; -// w->extents = win_extents(dpy, w); -// } -// } -// } -// } -// break; -// default: -// if (ev.type == damage_event + XDamageNotify) { -// fprintf(stderr, "XDamageNotify"); -// damage_win(dpy, (XDamageNotifyEvent *)&ev); -// } else if (ev.type == xshape_event + ShapeNotify) { -// fprintf(stderr, "ShapeNotify"); -// shape_win(dpy, (XShapeEvent *)&ev); -// } -// break; -// } -// } -// } +static void wComposerProcessDamageEvent(Display *dpy, XDamageNotifyEvent *de) +{ + CMPWindow *w = find_window(dpy, de->drawable); -#include "WM/core/log_utils.h" + if (!w) { + return; + } + repair_window(dpy, w); +} + +static void wComposerProcessShapeEvent(Display *dpy, XShapeEvent *se) +{ + CMPWindow *w = find_window(dpy, se->window); + + if (!w) { + return; + } + if (se->kind == ShapeClip || se->kind == ShapeBounding) { + XserverRegion region0; + XserverRegion region1; + + clipChanged = True; + + region0 = XFixesCreateRegion(dpy, &w->shape_bounds, 1); + + if (se->shaped == True) { + w->shaped = True; + w->shape_bounds.x = w->a.x + se->x; + w->shape_bounds.y = w->a.y + se->y; + w->shape_bounds.width = se->width; + w->shape_bounds.height = se->height; + } else { + w->shaped = False; + w->shape_bounds.x = w->a.x; + w->shape_bounds.y = w->a.y; + w->shape_bounds.width = w->a.width; + w->shape_bounds.height = w->a.height; + } + + region1 = XFixesCreateRegion(dpy, &w->shape_bounds, 1); + XFixesUnionRegion(dpy, region0, region0, region1); + XFixesDestroyRegion(dpy, region1); + + /* ask for repaint of the old and new region */ + paint_all(dpy, region0); + } +} + +static XRectangle *expose_rects = NULL; +static int size_expose = 0; +static int n_expose = 0; +static int p; +void wComposerProcessEvent(Display *dpy, XEvent ev) +{ + if (!autoRedirect) { + switch (ev.type) { + case CreateNotify: + add_window(dpy, ev.xcreatewindow.window, 0); + break; + case ConfigureNotify: + configure_window(dpy, &ev.xconfigure); + break; + case DestroyNotify: + destroy_window(dpy, ev.xdestroywindow.window, True, True); + break; + case MapNotify: + map_window(dpy, ev.xmap.window, ev.xmap.serial, True); + break; + case UnmapNotify: + unmap_window(dpy, ev.xunmap.window, True); + break; + case ReparentNotify: + if (ev.xreparent.parent == root) { + add_window(dpy, ev.xreparent.window, 0); + } else { + destroy_window(dpy, ev.xreparent.window, False, True); + } + break; + case CirculateNotify: + circulate_windows(dpy, &ev.xcirculate); + break; + case Expose: + if (ev.xexpose.window == root) { + int more = ev.xexpose.count + 1; + if (n_expose == size_expose) { + if (expose_rects) { + expose_rects = realloc(expose_rects, (size_expose + more) * sizeof(XRectangle)); + size_expose += more; + } else { + expose_rects = malloc(more * sizeof(XRectangle)); + size_expose = more; + } + } + expose_rects[n_expose].x = ev.xexpose.x; + expose_rects[n_expose].y = ev.xexpose.y; + expose_rects[n_expose].width = ev.xexpose.width; + expose_rects[n_expose].height = ev.xexpose.height; + n_expose++; + if (ev.xexpose.count == 0) { + add_damage_region(dpy, XFixesCreateRegion(dpy, expose_rects, n_expose)); + n_expose = 0; + } + } + break; + case PropertyNotify: + for (p = 0; backgroundProps[p]; p++) { + if (ev.xproperty.atom == XInternAtom(dpy, backgroundProps[p], False)) { + if (rootTile) { + XClearArea(dpy, root, 0, 0, 0, 0, True); + XRenderFreePicture(dpy, rootTile); + rootTile = None; + break; + } + } + } + /* check if Trans property was changed */ + if (ev.xproperty.atom == opacityAtom) { + /* reset mode and redraw window */ + CMPWindow *w = find_window(dpy, ev.xproperty.window); + if (w) { + if (fadeTrans) { + double start, finish, step; + start = w->opacity * 1.0 / OPAQUE; + finish = get_window_opacity_value(dpy, w, 1.0); + if (start > finish) + step = fade_in_step; + else + step = fade_out_step; + set_fade(dpy, w, start, finish, step, NULL, False, True, False); + } else { + w->opacity = get_window_opacity_property(dpy, w, OPAQUE); + determine_mode(dpy, w); + if (w->shadow) { + XRenderFreePicture(dpy, w->shadow); + w->shadow = None; + w->extents = window_extents_region(dpy, w); + } + } + } + } + break; + default: + if (ev.type == damage_event + XDamageNotify) { + wComposerProcessDamageEvent(dpy, (XDamageNotifyEvent *)&ev); + } else if (ev.type == xshape_event + ShapeNotify) { + wComposerProcessShapeEvent(dpy, (XShapeEvent *)&ev); + } + break; + } + } +} + +#include "core/log_utils.h" void wComposerRunLoop() { struct pollfd ufd; XEvent ev; - XRectangle *expose_rects = NULL; - int size_expose = 0; - int n_expose = 0; - int p; + // XRectangle *expose_rects = NULL; + // int size_expose = 0; + // int n_expose = 0; + // int p; WMLogError("Composer: Entering runloop with X connection: %i", ConnectionNumber(dpy)); ufd.fd = ConnectionNumber(dpy); ufd.events = POLLIN; if (!autoRedirect) { - wComposerPaintAll(dpy, None); + paint_all(dpy, None); } for (;;) { @@ -1709,110 +1711,110 @@ void wComposerRunLoop() } XNextEvent(dpy, &ev); if ((ev.type & 0x7f) != KeymapNotify) { - discard_ignore(dpy, ev.xany.serial); - } - // wComposerProcessEvent(dpy, ev); - if (!autoRedirect) { - switch (ev.type) { - case CreateNotify: - wComposerAddWindow(dpy, ev.xcreatewindow.window, 0); - break; - case ConfigureNotify: - wComposerConfigureWindow(dpy, &ev.xconfigure); - break; - case DestroyNotify: - wComposerRemoveWindow(dpy, ev.xdestroywindow.window, True, True); - break; - case MapNotify: - wComposerMapWindow(dpy, ev.xmap.window, ev.xmap.serial, True); - break; - case UnmapNotify: - wComposerUnmapWindow(dpy, ev.xunmap.window, True); - break; - case ReparentNotify: - if (ev.xreparent.parent == root) { - wComposerAddWindow(dpy, ev.xreparent.window, 0); - } else { - wComposerRemoveWindow(dpy, ev.xreparent.window, False, True); - } - break; - case CirculateNotify: - circulate_win(dpy, &ev.xcirculate); - break; - case Expose: - if (ev.xexpose.window == root) { - int more = ev.xexpose.count + 1; - if (n_expose == size_expose) { - if (expose_rects) { - expose_rects = realloc(expose_rects, (size_expose + more) * sizeof(XRectangle)); - size_expose += more; - } else { - expose_rects = malloc(more * sizeof(XRectangle)); - size_expose = more; - } - } - expose_rects[n_expose].x = ev.xexpose.x; - expose_rects[n_expose].y = ev.xexpose.y; - expose_rects[n_expose].width = ev.xexpose.width; - expose_rects[n_expose].height = ev.xexpose.height; - n_expose++; - if (ev.xexpose.count == 0) { - expose_root(dpy, root, expose_rects, n_expose); - n_expose = 0; - } - } - break; - case PropertyNotify: - for (p = 0; backgroundProps[p]; p++) { - if (ev.xproperty.atom == XInternAtom(dpy, backgroundProps[p], False)) { - if (rootTile) { - XClearArea(dpy, root, 0, 0, 0, 0, True); - XRenderFreePicture(dpy, rootTile); - rootTile = None; - break; - } - } - } - /* check if Trans property was changed */ - if (ev.xproperty.atom == opacityAtom) { - /* reset mode and redraw window */ - win *w = find_win(dpy, ev.xproperty.window); - if (w) { - if (fadeTrans) { - double start, finish, step; - start = w->opacity * 1.0 / OPAQUE; - finish = get_opacity_percent(dpy, w, 1.0); - if (start > finish) - step = fade_in_step; - else - step = fade_out_step; - set_fade(dpy, w, start, finish, step, NULL, False, True, False); - } else { - w->opacity = get_opacity_prop(dpy, w, OPAQUE); - determine_mode(dpy, w); - if (w->shadow) { - XRenderFreePicture(dpy, w->shadow); - w->shadow = None; - w->extents = win_extents(dpy, w); - } - } - } - } - break; - default: - if (ev.type == damage_event + XDamageNotify) { - wComposerProcessDamageEvent(dpy, (XDamageNotifyEvent *)&ev); - } else if (ev.type == xshape_event + ShapeNotify) { - shape_win(dpy, (XShapeEvent *)&ev); - } - break; - } + wComposerDiscardEventIgnore(dpy, ev.xany.serial); } + wComposerProcessEvent(dpy, ev); + // if (!autoRedirect) { + // switch (ev.type) { + // case CreateNotify: + // wComposerAddWindow(dpy, ev.xcreatewindow.window, 0); + // break; + // case ConfigureNotify: + // wComposerConfigureWindow(dpy, &ev.xconfigure); + // break; + // case DestroyNotify: + // wComposerRemoveWindow(dpy, ev.xdestroywindow.window, True, True); + // break; + // case MapNotify: + // wComposerMapWindow(dpy, ev.xmap.window, ev.xmap.serial, True); + // break; + // case UnmapNotify: + // wComposerUnmapWindow(dpy, ev.xunmap.window, True); + // break; + // case ReparentNotify: + // if (ev.xreparent.parent == root) { + // wComposerAddWindow(dpy, ev.xreparent.window, 0); + // } else { + // wComposerRemoveWindow(dpy, ev.xreparent.window, False, True); + // } + // break; + // case CirculateNotify: + // circulate_win(dpy, &ev.xcirculate); + // break; + // case Expose: + // if (ev.xexpose.window == root) { + // int more = ev.xexpose.count + 1; + // if (n_expose == size_expose) { + // if (expose_rects) { + // expose_rects = realloc(expose_rects, (size_expose + more) * sizeof(XRectangle)); + // size_expose += more; + // } else { + // expose_rects = malloc(more * sizeof(XRectangle)); + // size_expose = more; + // } + // } + // expose_rects[n_expose].x = ev.xexpose.x; + // expose_rects[n_expose].y = ev.xexpose.y; + // expose_rects[n_expose].width = ev.xexpose.width; + // expose_rects[n_expose].height = ev.xexpose.height; + // n_expose++; + // if (ev.xexpose.count == 0) { + // expose_root(dpy, root, expose_rects, n_expose); + // n_expose = 0; + // } + // } + // break; + // case PropertyNotify: + // for (p = 0; backgroundProps[p]; p++) { + // if (ev.xproperty.atom == XInternAtom(dpy, backgroundProps[p], False)) { + // if (rootTile) { + // XClearArea(dpy, root, 0, 0, 0, 0, True); + // XRenderFreePicture(dpy, rootTile); + // rootTile = None; + // break; + // } + // } + // } + // /* check if Trans property was changed */ + // if (ev.xproperty.atom == opacityAtom) { + // /* reset mode and redraw window */ + // win *w = find_win(dpy, ev.xproperty.window); + // if (w) { + // if (fadeTrans) { + // double start, finish, step; + // start = w->opacity * 1.0 / OPAQUE; + // finish = get_opacity_percent(dpy, w, 1.0); + // if (start > finish) + // step = fade_in_step; + // else + // step = fade_out_step; + // set_fade(dpy, w, start, finish, step, NULL, False, True, False); + // } else { + // w->opacity = get_opacity_prop(dpy, w, OPAQUE); + // determine_mode(dpy, w); + // if (w->shadow) { + // XRenderFreePicture(dpy, w->shadow); + // w->shadow = None; + // w->extents = win_extents(dpy, w); + // } + // } + // } + // } + // break; + // default: + // if (ev.type == damage_event + XDamageNotify) { + // wComposerProcessDamageEvent(dpy, (XDamageNotifyEvent *)&ev); + // } else if (ev.type == xshape_event + ShapeNotify) { + // shape_win(dpy, (XShapeEvent *)&ev); + // } + // break; + // } + // } } while (QLength(dpy)); if (allDamage && !autoRedirect) { static int paint; - wComposerPaintAll(dpy, allDamage); + paint_all(dpy, allDamage); paint++; XSync(dpy, False); allDamage = None; @@ -2020,9 +2022,9 @@ Bool wComposerInitialize() rootPicture = XRenderCreatePicture( dpy, root, XRenderFindVisualFormat(dpy, DefaultVisual(dpy, scr)), CPSubwindowMode, &pa); - blackPicture = wComposerCreateSolidPicture(dpy, True, 1, 0, 0, 0); + blackPicture = create_solid_picture(dpy, True, 1, 0, 0, 0); if (compMode == CompServerShadows) { - transBlackPicture = wComposerCreateSolidPicture(dpy, True, 0.3, 0, 0, 0); + transBlackPicture = create_solid_picture(dpy, True, 0.3, 0, 0, 0); } allDamage = None; clipChanged = True; @@ -2037,7 +2039,7 @@ Bool wComposerInitialize() XShapeSelectInput(dpy, root, ShapeNotifyMask); XQueryTree(dpy, root, &root_return, &parent_return, &children, &nchildren); for (unsigned int i = 0; i < nchildren; i++) - wComposerAddWindow(dpy, children[i], i ? children[i - 1] : None); + add_window(dpy, children[i], i ? children[i - 1] : None); XFree(children); } XUngrabServer(dpy); diff --git a/Applications/Workspace/WM/wmcomposer.h b/Applications/Workspace/WM/wmcomposer.h new file mode 100644 index 000000000..8ded901c4 --- /dev/null +++ b/Applications/Workspace/WM/wmcomposer.h @@ -0,0 +1,5 @@ +#include + +Bool wComposerInitialize(); +void wComposerRunLoop(); +Bool wComposerErrorHandler(Display *dpy, XErrorEvent *ev); \ No newline at end of file From e382e5915ff4db4da2bbf9ba426d5f4ed8b51eb2 Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Fri, 13 Oct 2023 19:14:26 +0300 Subject: [PATCH 11/67] fixed background color setting with composer. --- Applications/Workspace/WM/shutdown.c | 1 + Applications/Workspace/WM/wmcomposer.c | 9 +++--- Applications/Workspace/WM/wmcomposer.h | 1 + Frameworks/SystemKit/OSEScreen.m | 40 ++++++++++++++++++++++++++ 4 files changed, 47 insertions(+), 4 deletions(-) diff --git a/Applications/Workspace/WM/shutdown.c b/Applications/Workspace/WM/shutdown.c index 632146a66..b9da1d1f6 100644 --- a/Applications/Workspace/WM/shutdown.c +++ b/Applications/Workspace/WM/shutdown.c @@ -113,6 +113,7 @@ void wShutdown(WMShutdownMode mode) wScreenSaveState(scr); wNETWMCleanup(scr); /* Delete _NET_* Atoms */ PropCleanUp(scr->root_win); /* WM specific properties */ + XDeleteProperty(dpy, scr->root_win, XInternAtom(dpy, "_XROOTPMAP_ID", False)); RShutdown(); /* wraster clean exit */ #if HAVE_SYSLOG_H WMSyslogClose(); diff --git a/Applications/Workspace/WM/wmcomposer.c b/Applications/Workspace/WM/wmcomposer.c index 2a4ed83c7..ba1d19c40 100644 --- a/Applications/Workspace/WM/wmcomposer.c +++ b/Applications/Workspace/WM/wmcomposer.c @@ -684,10 +684,11 @@ static Picture root_tile_picture(Display *dpy) pixmap = None; for (p = 0; backgroundProps[p]; p++) { - if (XGetWindowProperty(dpy, root, XInternAtom(dpy, backgroundProps[p], False), 0, 4, False, - AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes_after, - &prop) == Success && - actual_type == XInternAtom(dpy, "PIXMAP", False) && actual_format == 32 && nitems == 1) { + int result = XGetWindowProperty(dpy, root, XInternAtom(dpy, backgroundProps[p], False), 0, 4, + False, AnyPropertyType, &actual_type, &actual_format, &nitems, + &bytes_after, &prop); + if (result == Success && actual_type == XInternAtom(dpy, "PIXMAP", False) && + actual_format == 32 && nitems == 1) { memcpy(&pixmap, prop, 4); XFree(prop); fill = False; diff --git a/Applications/Workspace/WM/wmcomposer.h b/Applications/Workspace/WM/wmcomposer.h index 8ded901c4..1a678f9f6 100644 --- a/Applications/Workspace/WM/wmcomposer.h +++ b/Applications/Workspace/WM/wmcomposer.h @@ -2,4 +2,5 @@ Bool wComposerInitialize(); void wComposerRunLoop(); +void wComposerProcessEvent(XEvent ev); Bool wComposerErrorHandler(Display *dpy, XErrorEvent *ev); \ No newline at end of file diff --git a/Frameworks/SystemKit/OSEScreen.m b/Frameworks/SystemKit/OSEScreen.m index 5e9342ff8..8ee54d369 100644 --- a/Frameworks/SystemKit/OSEScreen.m +++ b/Frameworks/SystemKit/OSEScreen.m @@ -34,6 +34,8 @@ */ #import +#include +#include #import #import #include @@ -530,6 +532,42 @@ - (BOOL)backgroundColorRed:(CGFloat *)redComponent return success; } +- (void)_setBackgroundXColor:(XColor)xColor + forXScreen:(Screen *)xScreen +{ + Atom rootpmap_id = XInternAtom(xDisplay, "_XROOTPMAP_ID", False); + Atom type; + int format; + unsigned long length, after; + unsigned char *data = 0; + Pixmap pixmap = None; + + // Clear out the old _XROOTPMAP_ID property + int result = XGetWindowProperty(xDisplay, xRootWindow, rootpmap_id, 0, 1, True, AnyPropertyType, + &type, &format, &length, &after, &data); + + if (result == Success && data && type == XA_PIXMAP && format == 32 && length == 1) { + // XKillClient(xDisplay, *((Pixmap *)data)); + XFree(data); + } + + // Set new _XROOTPMAP_ID property + pixmap = XCreatePixmap(xDisplay, xRootWindow, 8, 8, DefaultDepth(xDisplay, 0)); + if (pixmap != None) { + XGCValues gc_values; + gc_values.foreground = xColor.pixel; + gc_values.background = xColor.pixel; + gc_values.function = GXcopy; + GC gc = XCreateGC(xDisplay, xRootWindow, (GCForeground | GCBackground), &gc_values); + + XFillRectangle(xDisplay, pixmap, gc, 0, 0, 8, 8); + XChangeProperty(xDisplay, xRootWindow, rootpmap_id, XA_PIXMAP, 32, PropModeReplace, + (unsigned char *)&pixmap, 1); + XFreeGC(xDisplay, gc); + // XFreePixmap(xDisplay, pixmap); + } +} + - (BOOL)setBackgroundColorRed:(CGFloat)redComponent green:(CGFloat)greenComponent blue:(CGFloat)blueComponent @@ -561,7 +599,9 @@ - (BOOL)setBackgroundColorRed:(CGFloat)redComponent XSetWindowBackground(xDisplay, xRootWindow, xColor.pixel); XClearWindow(xDisplay, xRootWindow); + [self _setBackgroundXColor:xColor forXScreen:xScreen]; XSync(xDisplay, False); + return YES; } From 718863b0d13b621af9a0de82c089f521a956aef5 Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Mon, 16 Oct 2023 01:29:56 +0300 Subject: [PATCH 12/67] set root window background pixmap with _ROOTPMAP_ID property name to be catched by composer later. --- Frameworks/SystemKit/OSEScreen.m | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Frameworks/SystemKit/OSEScreen.m b/Frameworks/SystemKit/OSEScreen.m index 8ee54d369..f8bcbf82c 100644 --- a/Frameworks/SystemKit/OSEScreen.m +++ b/Frameworks/SystemKit/OSEScreen.m @@ -552,15 +552,13 @@ - (void)_setBackgroundXColor:(XColor)xColor } // Set new _XROOTPMAP_ID property - pixmap = XCreatePixmap(xDisplay, xRootWindow, 8, 8, DefaultDepth(xDisplay, 0)); + pixmap = XCreatePixmap(xDisplay, xRootWindow, 1, 1, DefaultDepth(xDisplay, 0)); if (pixmap != None) { XGCValues gc_values; gc_values.foreground = xColor.pixel; - gc_values.background = xColor.pixel; - gc_values.function = GXcopy; - GC gc = XCreateGC(xDisplay, xRootWindow, (GCForeground | GCBackground), &gc_values); + GC gc = XCreateGC(xDisplay, xRootWindow, GCForeground, &gc_values); - XFillRectangle(xDisplay, pixmap, gc, 0, 0, 8, 8); + XFillRectangle(xDisplay, pixmap, gc, 0, 0, 1, 1); XChangeProperty(xDisplay, xRootWindow, rootpmap_id, XA_PIXMAP, 32, PropModeReplace, (unsigned char *)&pixmap, 1); XFreeGC(xDisplay, gc); @@ -596,9 +594,11 @@ - (BOOL)setBackgroundColorRed:(CGFloat)redComponent x_color_spec); return NO; } - + + // Set background for non-compositor sessions XSetWindowBackground(xDisplay, xRootWindow, xColor.pixel); XClearWindow(xDisplay, xRootWindow); + // Set background for sessions with compositor [self _setBackgroundXColor:xColor forXScreen:xScreen]; XSync(xDisplay, False); From a0c7c5008fcb5330a08ed99471c4b25ab6773750 Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Mon, 16 Oct 2023 01:33:26 +0300 Subject: [PATCH 13/67] use OSEScreen method to set root window background. --- Applications/Login/Controller.m | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Applications/Login/Controller.m b/Applications/Login/Controller.m index e0cd7a3ae..73419cc00 100644 --- a/Applications/Login/Controller.m +++ b/Applications/Login/Controller.m @@ -20,6 +20,7 @@ // #import "Controller.h" +#include "Foundation/NSObjCRuntime.h" #import "UserSession.h" #import @@ -31,6 +32,7 @@ #endif #import +#import #import #import @@ -169,9 +171,9 @@ - (void)setRootWindowBackground winattrs.cursor = XCreateFontCursor(xDisplay, XC_left_ptr); XChangeWindowAttributes(xDisplay, xRootWindow, CWCursor, &winattrs); - XSetWindowBackground(xDisplay, xRootWindow, 5460853L); - XClearWindow(xDisplay, xRootWindow); - XSync(xDisplay, false); + [[OSEScreen sharedScreen] setBackgroundColorRed:83.0 / 255.0 + green:83.0 / 255.0 + blue:116.0 / 255.0]; } - (void)setWindowVisible:(BOOL)flag From 35e88e844065e8c4652ffb07bfb4a7e980043644 Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Mon, 16 Oct 2023 01:33:57 +0300 Subject: [PATCH 14/67] start composer after WM initialization but before WM runloop. --- Applications/Workspace/Workspace_main.m | 46 ++++++++++++------------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/Applications/Workspace/Workspace_main.m b/Applications/Workspace/Workspace_main.m index 2af6ad283..dd959d397 100644 --- a/Applications/Workspace/Workspace_main.m +++ b/Applications/Workspace/Workspace_main.m @@ -125,6 +125,9 @@ int WSApplicationMain(int argc, const char **argv) int main(int argc, const char **argv) { + dispatch_queue_t composer_q; + dispatch_queue_t window_manager_q; + if (_isWindowServerReady() == NO) { fprintf(stderr, "[Workspace] X Window server is not ready on display '%s'\n", getenv("DISPLAY")); @@ -138,31 +141,14 @@ int main(int argc, const char **argv) fprintf(stderr, "=== Starting Workspace ===\n"); workspace_q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0); - - //--- Compositor thread queue ------------------------------------- - { - dispatch_queue_t cmp_q; - cmp_q = dispatch_queue_create("ns.workspace.composer", DISPATCH_QUEUE_CONCURRENT); - dispatch_async(cmp_q, ^{ - fprintf(stderr, "=== Initializing Composer ===\n"); - if (wComposerInitialize() == True) { - fprintf(stderr, "=== Composer initialized ===\n"); - wComposerRunLoop(); - fprintf(stderr, "=== Composer completed it's execution ===\n"); - } else { - fprintf(stderr, "=== Failed to initialize Composer ===\n"); - } - }); - } - - //--- Window Manager thread queue ------------------------------------- { - dispatch_queue_t wm_q; - + composer_q = dispatch_queue_create("ns.workspace.composer", DISPATCH_QUEUE_CONCURRENT); // DISPATCH_QUEUE_CONCURRENT is mandatory for CFRunLoop run. - wm_q = dispatch_queue_create("ns.workspace.wm", DISPATCH_QUEUE_CONCURRENT); + window_manager_q = dispatch_queue_create("ns.workspace.wm", DISPATCH_QUEUE_CONCURRENT); + + //--- Initialize Window Manager fprintf(stderr, "=== Initializing Window Manager ===\n"); - dispatch_sync(wm_q, ^{ + dispatch_sync(window_manager_q, ^{ @autoreleasepool { // Restore display layout [[[OSEScreen new] autorelease] applySavedDisplayLayout]; @@ -175,11 +161,23 @@ int main(int argc, const char **argv) }); fprintf(stderr, "=== Window Manager initialized! ===\n"); + //--- Start Composer + dispatch_async(composer_q, ^{ + fprintf(stderr, "=== Initializing Composer ===\n"); + if (wComposerInitialize() == True) { + fprintf(stderr, "=== Composer initialized ===\n"); + wComposerRunLoop(); + fprintf(stderr, "=== Composer completed it's execution ===\n"); + } else { + fprintf(stderr, "=== Failed to initialize Composer ===\n"); + } + }); + // Start WM run loop V0 to catch events while V1 is warming up. - dispatch_async(wm_q, ^{ + dispatch_async(window_manager_q, ^{ WMRunLoop_V0(); }); - dispatch_async(wm_q, ^{ + dispatch_async(window_manager_q, ^{ WMRunLoop_V1(); }); } From f09bb3f7e8de4cfe53388aa7040d8ab2515fd748 Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Mon, 16 Oct 2023 01:51:54 +0300 Subject: [PATCH 15/67] removed unused code and made cleanup. --- Applications/Workspace/WM/wmcomposer.c | 178 +++++-------------------- 1 file changed, 37 insertions(+), 141 deletions(-) diff --git a/Applications/Workspace/WM/wmcomposer.c b/Applications/Workspace/WM/wmcomposer.c index ba1d19c40..0ea09ab0b 100644 --- a/Applications/Workspace/WM/wmcomposer.c +++ b/Applications/Workspace/WM/wmcomposer.c @@ -24,6 +24,7 @@ says above. Not that I can really do anything about it */ +#include #include #include #include @@ -490,7 +491,7 @@ static void presum_gaussian(conv *map) } // ---------------------------------------------------------------------------------------------- -// Pictures and images +// Pictures, images and painting // ---------------------------------------------------------------------------------------------- static XImage *create_shadow_image(Display *dpy, double opacity, int width, int height) { @@ -662,47 +663,35 @@ static Picture create_solid_picture(Display *dpy, Bool argb, double a, double r, return picture; } - -static const char *backgroundProps[] = { - "_XROOTPMAP_ID", - "_XSETROOT_ID", - NULL, -}; - static Picture root_tile_picture(Display *dpy) { Picture picture; Atom actual_type; - Pixmap pixmap; + Pixmap pixmap = None; int actual_format; unsigned long nitems; unsigned long bytes_after; unsigned char *prop; - Bool fill; + Bool shouldFill = False; XRenderPictureAttributes pa; - int p; - - pixmap = None; - for (p = 0; backgroundProps[p]; p++) { - int result = XGetWindowProperty(dpy, root, XInternAtom(dpy, backgroundProps[p], False), 0, 4, - False, AnyPropertyType, &actual_type, &actual_format, &nitems, - &bytes_after, &prop); - if (result == Success && actual_type == XInternAtom(dpy, "PIXMAP", False) && - actual_format == 32 && nitems == 1) { - memcpy(&pixmap, prop, 4); - XFree(prop); - fill = False; - break; - } + + int result = XGetWindowProperty(dpy, root, XInternAtom(dpy, "_XROOTPMAP_ID", False), 0, 4, False, + AnyPropertyType, &actual_type, &actual_format, &nitems, + &bytes_after, &prop); + if (result == Success && actual_type == XInternAtom(dpy, "PIXMAP", False) && + actual_format == 32 && nitems == 1) { + memcpy(&pixmap, prop, 4); + XFree(prop); } + if (!pixmap) { pixmap = XCreatePixmap(dpy, root, 1, 1, DefaultDepth(dpy, scr)); - fill = True; + shouldFill = True; } pa.repeat = True; picture = XRenderCreatePicture(dpy, pixmap, XRenderFindVisualFormat(dpy, DefaultVisual(dpy, scr)), CPRepeat, &pa); - if (fill) { + if (shouldFill) { XRenderColor c; // c.red = c.green = c.blue = 0x8080; @@ -1580,7 +1569,6 @@ static void wComposerProcessShapeEvent(Display *dpy, XShapeEvent *se) static XRectangle *expose_rects = NULL; static int size_expose = 0; static int n_expose = 0; -static int p; void wComposerProcessEvent(Display *dpy, XEvent ev) { if (!autoRedirect) { @@ -1634,14 +1622,12 @@ void wComposerProcessEvent(Display *dpy, XEvent ev) } break; case PropertyNotify: - for (p = 0; backgroundProps[p]; p++) { - if (ev.xproperty.atom == XInternAtom(dpy, backgroundProps[p], False)) { - if (rootTile) { - XClearArea(dpy, root, 0, 0, 0, 0, True); - XRenderFreePicture(dpy, rootTile); - rootTile = None; - break; - } + if (ev.xproperty.atom == XInternAtom(dpy, "_XROOTPMAP_ID", False)) { + if (rootTile) { + XClearArea(dpy, root, 0, 0, 0, 0, True); + XRenderFreePicture(dpy, rootTile); + rootTile = None; + break; } } /* check if Trans property was changed */ @@ -1715,102 +1701,6 @@ void wComposerRunLoop() wComposerDiscardEventIgnore(dpy, ev.xany.serial); } wComposerProcessEvent(dpy, ev); - // if (!autoRedirect) { - // switch (ev.type) { - // case CreateNotify: - // wComposerAddWindow(dpy, ev.xcreatewindow.window, 0); - // break; - // case ConfigureNotify: - // wComposerConfigureWindow(dpy, &ev.xconfigure); - // break; - // case DestroyNotify: - // wComposerRemoveWindow(dpy, ev.xdestroywindow.window, True, True); - // break; - // case MapNotify: - // wComposerMapWindow(dpy, ev.xmap.window, ev.xmap.serial, True); - // break; - // case UnmapNotify: - // wComposerUnmapWindow(dpy, ev.xunmap.window, True); - // break; - // case ReparentNotify: - // if (ev.xreparent.parent == root) { - // wComposerAddWindow(dpy, ev.xreparent.window, 0); - // } else { - // wComposerRemoveWindow(dpy, ev.xreparent.window, False, True); - // } - // break; - // case CirculateNotify: - // circulate_win(dpy, &ev.xcirculate); - // break; - // case Expose: - // if (ev.xexpose.window == root) { - // int more = ev.xexpose.count + 1; - // if (n_expose == size_expose) { - // if (expose_rects) { - // expose_rects = realloc(expose_rects, (size_expose + more) * sizeof(XRectangle)); - // size_expose += more; - // } else { - // expose_rects = malloc(more * sizeof(XRectangle)); - // size_expose = more; - // } - // } - // expose_rects[n_expose].x = ev.xexpose.x; - // expose_rects[n_expose].y = ev.xexpose.y; - // expose_rects[n_expose].width = ev.xexpose.width; - // expose_rects[n_expose].height = ev.xexpose.height; - // n_expose++; - // if (ev.xexpose.count == 0) { - // expose_root(dpy, root, expose_rects, n_expose); - // n_expose = 0; - // } - // } - // break; - // case PropertyNotify: - // for (p = 0; backgroundProps[p]; p++) { - // if (ev.xproperty.atom == XInternAtom(dpy, backgroundProps[p], False)) { - // if (rootTile) { - // XClearArea(dpy, root, 0, 0, 0, 0, True); - // XRenderFreePicture(dpy, rootTile); - // rootTile = None; - // break; - // } - // } - // } - // /* check if Trans property was changed */ - // if (ev.xproperty.atom == opacityAtom) { - // /* reset mode and redraw window */ - // win *w = find_win(dpy, ev.xproperty.window); - // if (w) { - // if (fadeTrans) { - // double start, finish, step; - // start = w->opacity * 1.0 / OPAQUE; - // finish = get_opacity_percent(dpy, w, 1.0); - // if (start > finish) - // step = fade_in_step; - // else - // step = fade_out_step; - // set_fade(dpy, w, start, finish, step, NULL, False, True, False); - // } else { - // w->opacity = get_opacity_prop(dpy, w, OPAQUE); - // determine_mode(dpy, w); - // if (w->shadow) { - // XRenderFreePicture(dpy, w->shadow); - // w->shadow = None; - // w->extents = win_extents(dpy, w); - // } - // } - // } - // } - // break; - // default: - // if (ev.type == damage_event + XDamageNotify) { - // wComposerProcessDamageEvent(dpy, (XDamageNotifyEvent *)&ev); - // } else if (ev.type == xshape_event + ShapeNotify) { - // shape_win(dpy, (XShapeEvent *)&ev); - // } - // break; - // } - // } } while (QLength(dpy)); if (allDamage && !autoRedirect) { @@ -1830,22 +1720,23 @@ void wComposerRunLoop() static Bool wComposerRegister(Display *dpy) { - Window w; - Atom a; + Window window; + Atom atom; static char net_wm_cm[] = "_NET_WM_CM_Sxx"; + // EWMH 1.4.draft-2 snprintf(net_wm_cm, sizeof(net_wm_cm), "_NET_WM_CM_S%d", scr); - a = XInternAtom(dpy, net_wm_cm, False); + atom = XInternAtom(dpy, net_wm_cm, False); - w = XGetSelectionOwner(dpy, a); - if (w != None) { + window = XGetSelectionOwner(dpy, atom); + if (window != None) { XTextProperty tp; char **strs; int count; Atom winNameAtom = XInternAtom(dpy, "_NET_WM_NAME", False); - if (!XGetTextProperty(dpy, w, &tp, winNameAtom) && !XGetTextProperty(dpy, w, &tp, XA_WM_NAME)) { - fprintf(stderr, "Another composite manager is already running (0x%lx)\n", (unsigned long)w); + if (!XGetTextProperty(dpy, window, &tp, winNameAtom) && !XGetTextProperty(dpy, window, &tp, XA_WM_NAME)) { + fprintf(stderr, "Another composite manager is already running (0x%lx)\n", (unsigned long)window); return False; } if (XmbTextPropertyToTextList(dpy, &tp, &strs, &count) == Success) { @@ -1859,11 +1750,11 @@ static Bool wComposerRegister(Display *dpy) return False; } - w = XCreateSimpleWindow(dpy, RootWindow(dpy, scr), 0, 0, 1, 1, 0, None, None); + window = XCreateSimpleWindow(dpy, RootWindow(dpy, scr), 0, 0, 1, 1, 0, None, None); - Xutf8SetWMProperties(dpy, w, "xcompmgr", "xcompmgr", NULL, 0, NULL, NULL, NULL); + Xutf8SetWMProperties(dpy, window, "Composer", "xcompmgr", NULL, 0, NULL, NULL, NULL); - XSetSelectionOwner(dpy, a, w, 0); + XSetSelectionOwner(dpy, atom, window, 0); return True; } @@ -2047,3 +1938,8 @@ Bool wComposerInitialize() return True; } + +void wComposerShutdown() +{ + + } From a378e9d8286d68d69b15fc4e17f4aeab88274c2c Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Mon, 16 Oct 2023 13:33:21 +0300 Subject: [PATCH 16/67] compile_flags added to applications --- Applications/Login/compile_flags.txt | 1 + Applications/OpenUp/compile_flags.txt | 1 + Applications/Preferences/compile_flags.txt | 1 + Applications/Review/compile_flags.txt | 1 + Applications/Terminal/compile_flags.txt | 28 +----------------- Applications/TextEdit/compile_flags.txt | 1 + Applications/TimeMon/compile_flags.txt | 1 + compile_flags.txt | 33 ++++++++++++++++++++++ 8 files changed, 40 insertions(+), 27 deletions(-) create mode 120000 Applications/Login/compile_flags.txt create mode 120000 Applications/OpenUp/compile_flags.txt create mode 120000 Applications/Preferences/compile_flags.txt create mode 120000 Applications/Review/compile_flags.txt mode change 100644 => 120000 Applications/Terminal/compile_flags.txt create mode 120000 Applications/TextEdit/compile_flags.txt create mode 120000 Applications/TimeMon/compile_flags.txt create mode 100644 compile_flags.txt diff --git a/Applications/Login/compile_flags.txt b/Applications/Login/compile_flags.txt new file mode 120000 index 000000000..7a643aa9f --- /dev/null +++ b/Applications/Login/compile_flags.txt @@ -0,0 +1 @@ +../../compile_flags.txt \ No newline at end of file diff --git a/Applications/OpenUp/compile_flags.txt b/Applications/OpenUp/compile_flags.txt new file mode 120000 index 000000000..7a643aa9f --- /dev/null +++ b/Applications/OpenUp/compile_flags.txt @@ -0,0 +1 @@ +../../compile_flags.txt \ No newline at end of file diff --git a/Applications/Preferences/compile_flags.txt b/Applications/Preferences/compile_flags.txt new file mode 120000 index 000000000..7a643aa9f --- /dev/null +++ b/Applications/Preferences/compile_flags.txt @@ -0,0 +1 @@ +../../compile_flags.txt \ No newline at end of file diff --git a/Applications/Review/compile_flags.txt b/Applications/Review/compile_flags.txt new file mode 120000 index 000000000..7a643aa9f --- /dev/null +++ b/Applications/Review/compile_flags.txt @@ -0,0 +1 @@ +../../compile_flags.txt \ No newline at end of file diff --git a/Applications/Terminal/compile_flags.txt b/Applications/Terminal/compile_flags.txt deleted file mode 100644 index 7642bb6e4..000000000 --- a/Applications/Terminal/compile_flags.txt +++ /dev/null @@ -1,27 +0,0 @@ --MMD --MP --DGNUSTEP --DGNUSTEP_BASE_LIBRARY=1 --DGNU_GUI_LIBRARY=1 --DGNUSTEP_RUNTIME=1 --D_NONFRAGILE_ABI=1 --DGNUSTEP_BASE_LIBRARY=1 --fno-strict-aliasing --fexceptions --fobjc-exceptions --D_NATIVE_OBJC_EXCEPTIONS --pthread --fPIC --DDEBUG --fno-omit-frame-pointer --Wno-import --g --fobjc-runtime=gnustep-2.0 --fblocks --fconstant-string-class=NSConstantString --I. --I.. --I../.. --I/Users/me/Library/Headers --I/Developer/Headers --I/usr/NextSpace/include diff --git a/Applications/Terminal/compile_flags.txt b/Applications/Terminal/compile_flags.txt new file mode 120000 index 000000000..7a643aa9f --- /dev/null +++ b/Applications/Terminal/compile_flags.txt @@ -0,0 +1 @@ +../../compile_flags.txt \ No newline at end of file diff --git a/Applications/TextEdit/compile_flags.txt b/Applications/TextEdit/compile_flags.txt new file mode 120000 index 000000000..7a643aa9f --- /dev/null +++ b/Applications/TextEdit/compile_flags.txt @@ -0,0 +1 @@ +../../compile_flags.txt \ No newline at end of file diff --git a/Applications/TimeMon/compile_flags.txt b/Applications/TimeMon/compile_flags.txt new file mode 120000 index 000000000..7a643aa9f --- /dev/null +++ b/Applications/TimeMon/compile_flags.txt @@ -0,0 +1 @@ +../../compile_flags.txt \ No newline at end of file diff --git a/compile_flags.txt b/compile_flags.txt new file mode 100644 index 000000000..6e01e7ebd --- /dev/null +++ b/compile_flags.txt @@ -0,0 +1,33 @@ +-xobjective-c +-MMD +-MP +-DGNUSTEP +-DGNUSTEP_BASE_LIBRARY=1 +-DGNU_GUI_LIBRARY=1 +-DGNUSTEP_RUNTIME=1 +-D_NONFRAGILE_ABI=1 +-DGNUSTEP_BASE_LIBRARY=1 +-fno-strict-aliasing +-fexceptions +-fobjc-exceptions +-D_NATIVE_OBJC_EXCEPTIONS +-DHAVE_CONFIG_H +-DWITH_GNUSTEP +-D_XOPEN_SOURCE=600 +-D_GNU_SOURCE +-pthread +-fPIC +-DDEBUG +-fno-omit-frame-pointer +-Wall +-Wno-import +-Wno-unused-variable +-Wno-typedef-redefinition +-g +-fobjc-runtime=gnustep-2.0 +-fblocks +-fconstant-string-class=NSConstantString +-I. +-I/Users/me/Library/Headers +-I/Developer/Headers +-I/usr/NextSpace/include From fe4fb8e637daf6ec9f302fe11fedbf12efb3c447 Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Mon, 16 Oct 2023 13:35:24 +0300 Subject: [PATCH 17/67] compile_flags added to the missed Weather --- Applications/Weather/compile_flags.txt | 1 + 1 file changed, 1 insertion(+) create mode 120000 Applications/Weather/compile_flags.txt diff --git a/Applications/Weather/compile_flags.txt b/Applications/Weather/compile_flags.txt new file mode 120000 index 000000000..7a643aa9f --- /dev/null +++ b/Applications/Weather/compile_flags.txt @@ -0,0 +1 @@ +../../compile_flags.txt \ No newline at end of file From 843d41068bc57a231d0dfe83cba788473996f804 Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Mon, 16 Oct 2023 15:28:20 +0300 Subject: [PATCH 18/67] adopt background pixmap resource manipulation to be used by Login and Preferences without overhead and conflicts. Login creates and owns pixmap, Preferences non-destructive change of existing pixmap background color. --- Frameworks/SystemKit/OSEScreen.h | 14 ++++---- Frameworks/SystemKit/OSEScreen.m | 58 +++++++++++++++++++------------- 2 files changed, 43 insertions(+), 29 deletions(-) diff --git a/Frameworks/SystemKit/OSEScreen.h b/Frameworks/SystemKit/OSEScreen.h index eb66b5f94..049fe4833 100644 --- a/Frameworks/SystemKit/OSEScreen.h +++ b/Frameworks/SystemKit/OSEScreen.h @@ -71,17 +71,19 @@ @interface OSEScreen : NSObject { - Display *xDisplay; - Window xRootWindow; + @private + Display *xDisplay; + Window xRootWindow; - BOOL useAutosave; + Pixmap background_pixmap; + GC background_gc; + XGCValues background_gc_values; + id backgroundPixmapOwner; + BOOL useAutosave; NSLock *updateScreenLock; - XRRScreenResources *screen_resources; - NSMutableArray *systemDisplays; - NSSize sizeInPixels, sizeInMilimeters; } diff --git a/Frameworks/SystemKit/OSEScreen.m b/Frameworks/SystemKit/OSEScreen.m index f8bcbf82c..4f1741a6a 100644 --- a/Frameworks/SystemKit/OSEScreen.m +++ b/Frameworks/SystemKit/OSEScreen.m @@ -306,6 +306,8 @@ - (id)init } useAutosave = NO; + background_pixmap = None; + background_gc = None; // Workspace Manager notification sent as a reaction to XRRScreenChangeNotify [[NSDistributedNotificationCenter defaultCenter] @@ -329,7 +331,13 @@ - (void)dealloc [[NSDistributedNotificationCenter defaultCenter] removeObserver:self]; XRRFreeScreenResources(screen_resources); - + if (background_pixmap != None && backgroundPixmapOwner == self) { + XFree(&background_pixmap); + } + if (background_gc != None) { + XFreeGC(xDisplay, background_gc); + } + XCloseDisplay(xDisplay); [systemDisplays release]; @@ -536,33 +544,37 @@ - (void)_setBackgroundXColor:(XColor)xColor forXScreen:(Screen *)xScreen { Atom rootpmap_id = XInternAtom(xDisplay, "_XROOTPMAP_ID", False); - Atom type; - int format; - unsigned long length, after; - unsigned char *data = 0; - Pixmap pixmap = None; - - // Clear out the old _XROOTPMAP_ID property - int result = XGetWindowProperty(xDisplay, xRootWindow, rootpmap_id, 0, 1, True, AnyPropertyType, - &type, &format, &length, &after, &data); - - if (result == Success && data && type == XA_PIXMAP && format == 32 && length == 1) { - // XKillClient(xDisplay, *((Pixmap *)data)); - XFree(data); + + if (background_pixmap == None) { + // Try to get existing _XROOTPMAP_ID property + Atom type; + int format; + unsigned long length, after; + unsigned char *data = 0; + int result = XGetWindowProperty(xDisplay, xRootWindow, rootpmap_id, 0, 1, True, AnyPropertyType, + &type, &format, &length, &after, &data); + + if (result == Success && data && type == XA_PIXMAP && format == 32 && length == 1) { + // Do not clear out - owner may still exist (Login.app) + // XKillClient(xDisplay, *((Pixmap *)data)); + // XFree(data); + background_pixmap = *((Pixmap *)data); + } else { + background_pixmap = XCreatePixmap(xDisplay, xRootWindow, 1, 1, DefaultDepth(xDisplay, 0)); + backgroundPixmapOwner = self; + } + background_gc_values.foreground = xColor.pixel; + background_gc = XCreateGC(xDisplay, xRootWindow, GCForeground, &background_gc_values); } // Set new _XROOTPMAP_ID property - pixmap = XCreatePixmap(xDisplay, xRootWindow, 1, 1, DefaultDepth(xDisplay, 0)); - if (pixmap != None) { - XGCValues gc_values; - gc_values.foreground = xColor.pixel; - GC gc = XCreateGC(xDisplay, xRootWindow, GCForeground, &gc_values); + if (background_pixmap != None) { + background_gc_values.foreground = xColor.pixel; + XChangeGC(xDisplay, background_gc, GCForeground, &background_gc_values); - XFillRectangle(xDisplay, pixmap, gc, 0, 0, 1, 1); + XFillRectangle(xDisplay, background_pixmap, background_gc, 0, 0, 1, 1); XChangeProperty(xDisplay, xRootWindow, rootpmap_id, XA_PIXMAP, 32, PropModeReplace, - (unsigned char *)&pixmap, 1); - XFreeGC(xDisplay, gc); - // XFreePixmap(xDisplay, pixmap); + (unsigned char *)&background_pixmap, 1); } } From 9a7922b2452a30f852d7b3a3690515153d68cded Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Mon, 16 Oct 2023 16:07:48 +0300 Subject: [PATCH 19/67] wmcomposer: renamed Xlib variables to underscore format --- Applications/Workspace/WM/wmcomposer.c | 180 ++++++++++++------------- 1 file changed, 89 insertions(+), 91 deletions(-) diff --git a/Applications/Workspace/WM/wmcomposer.c b/Applications/Workspace/WM/wmcomposer.c index 0ea09ab0b..c14e99a18 100644 --- a/Applications/Workspace/WM/wmcomposer.c +++ b/Applications/Workspace/WM/wmcomposer.c @@ -96,15 +96,15 @@ static Display *dpy; static CMPWindow *list; static CMPFade *fades; static int scr; -static Window root; -static Picture rootPicture; -static Picture rootBuffer; -static Picture blackPicture; -static Picture transBlackPicture; -static Picture rootTile; +static Window root_window; +static Picture root_picture; +static Picture root_picture_buffer; +static Picture root_picture_tile; +static Picture black_picture; +static Picture trans_black_picture; static XserverRegion allDamage; -static Bool clipChanged; -static Bool hasNamePixmap; +static Bool is_clip_changed; +static Bool has_name_pixmap; static int root_height, root_width; static CMPIgnoreSequence *ignore_head, **ignore_tail = &ignore_head; static int xfixes_event, xfixes_error; @@ -112,7 +112,7 @@ static int damage_event, damage_error; static int composite_event, composite_error; static int render_event, render_error; static int xshape_event, xshape_error; -static Bool synchronize; +static Bool should_synchronize; static int composite_opcode; /* find these once and be done with it */ @@ -127,9 +127,6 @@ static Atom winSplashAtom; static Atom winDialogAtom; static Atom winNormalAtom; -/* opacity property name; sometime soon I'll write up an EWMH spec for it */ -#define OPACITY_PROP "_NET_WM_WINDOW_OPACITY" - #define TRANSLUCENT 0xe0000000 #define OPAQUE 0xffffffff @@ -600,7 +597,7 @@ static Picture create_shadow_picture(Display *dpy, double opacity, Picture alpha if (!shadowImage) { return None; } - shadowPixmap = XCreatePixmap(dpy, root, shadowImage->width, shadowImage->height, 8); + shadowPixmap = XCreatePixmap(dpy, root_window, shadowImage->width, shadowImage->height, 8); if (!shadowPixmap) { XDestroyImage(shadowImage); return None; @@ -640,7 +637,7 @@ static Picture create_solid_picture(Display *dpy, Bool argb, double a, double r, XRenderColor c; XRenderPictFormat *pictureFormat; - pixmap = XCreatePixmap(dpy, root, 1, 1, argb ? 32 : 8); + pixmap = XCreatePixmap(dpy, root_window, 1, 1, argb ? 32 : 8); if (!pixmap) { return None; } @@ -675,7 +672,7 @@ static Picture root_tile_picture(Display *dpy) Bool shouldFill = False; XRenderPictureAttributes pa; - int result = XGetWindowProperty(dpy, root, XInternAtom(dpy, "_XROOTPMAP_ID", False), 0, 4, False, + int result = XGetWindowProperty(dpy, root_window, XInternAtom(dpy, "_XROOTPMAP_ID", False), 0, 4, False, AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes_after, &prop); if (result == Success && actual_type == XInternAtom(dpy, "PIXMAP", False) && @@ -685,7 +682,7 @@ static Picture root_tile_picture(Display *dpy) } if (!pixmap) { - pixmap = XCreatePixmap(dpy, root, 1, 1, DefaultDepth(dpy, scr)); + pixmap = XCreatePixmap(dpy, root_window, 1, 1, DefaultDepth(dpy, scr)); shouldFill = True; } pa.repeat = True; @@ -704,11 +701,11 @@ static Picture root_tile_picture(Display *dpy) static void paint_root_window(Display *dpy) { - if (!rootTile) { - rootTile = root_tile_picture(dpy); + if (!root_picture_tile) { + root_picture_tile = root_tile_picture(dpy); } - XRenderComposite(dpy, PictOpSrc, rootTile, None, rootBuffer, 0, 0, 0, 0, 0, 0, root_width, + XRenderComposite(dpy, PictOpSrc, root_picture_tile, None, root_picture_buffer, 0, 0, 0, 0, 0, 0, root_width, root_height); } @@ -725,13 +722,13 @@ static void paint_all(Display *dpy, XserverRegion region) r.height = root_height; region = XFixesCreateRegion(dpy, &r, 1); } - if (!rootBuffer) { - Pixmap rootPixmap = XCreatePixmap(dpy, root, root_width, root_height, DefaultDepth(dpy, scr)); - rootBuffer = XRenderCreatePicture( + if (!root_picture_buffer) { + Pixmap rootPixmap = XCreatePixmap(dpy, root_window, root_width, root_height, DefaultDepth(dpy, scr)); + root_picture_buffer = XRenderCreatePicture( dpy, rootPixmap, XRenderFindVisualFormat(dpy, DefaultVisual(dpy, scr)), 0, NULL); XFreePixmap(dpy, rootPixmap); } - XFixesSetPictureClipRegion(dpy, rootPicture, 0, 0, region); + XFixesSetPictureClipRegion(dpy, root_picture, 0, 0, region); for (w = list; w; w = w->next) { /* never painted, ignore it */ if (!w->damaged) { @@ -747,7 +744,7 @@ static void paint_all(Display *dpy, XserverRegion region) XRenderPictFormat *format; Drawable draw = w->id; - if (hasNamePixmap && !w->pixmap) { + if (has_name_pixmap && !w->pixmap) { w->pixmap = XCompositeNameWindowPixmap(dpy, w->id); } if (w->pixmap) { @@ -757,7 +754,7 @@ static void paint_all(Display *dpy, XserverRegion region) pa.subwindow_mode = IncludeInferiors; w->picture = XRenderCreatePicture(dpy, draw, format, CPSubwindowMode, &pa); } - if (clipChanged) { + if (is_clip_changed) { if (w->borderSize) { wComposerSetEventIgnore(dpy, NextRequest(dpy)); XFixesDestroyRegion(dpy, w->borderSize); @@ -784,11 +781,11 @@ static void paint_all(Display *dpy, XserverRegion region) y = w->a.y; wid = w->a.width + w->a.border_width * 2; hei = w->a.height + w->a.border_width * 2; - XFixesSetPictureClipRegion(dpy, rootBuffer, 0, 0, region); + XFixesSetPictureClipRegion(dpy, root_picture_buffer, 0, 0, region); wComposerSetEventIgnore(dpy, NextRequest(dpy)); XFixesSubtractRegion(dpy, region, region, w->borderSize); wComposerSetEventIgnore(dpy, NextRequest(dpy)); - XRenderComposite(dpy, PictOpSrc, w->picture, None, rootBuffer, 0, 0, 0, 0, x, y, wid, hei); + XRenderComposite(dpy, PictOpSrc, w->picture, None, root_picture_buffer, 0, 0, 0, 0, x, y, wid, hei); } if (!w->borderClip) { w->borderClip = XFixesCreateRegion(dpy, NULL, 0); @@ -797,10 +794,10 @@ static void paint_all(Display *dpy, XserverRegion region) w->prev_trans = t; t = w; } - XFixesSetPictureClipRegion(dpy, rootBuffer, 0, 0, region); + XFixesSetPictureClipRegion(dpy, root_picture_buffer, 0, 0, region); paint_root_window(dpy); for (w = t; w; w = w->prev_trans) { - XFixesSetPictureClipRegion(dpy, rootBuffer, 0, 0, w->borderClip); + XFixesSetPictureClipRegion(dpy, root_picture_buffer, 0, 0, w->borderClip); switch (compMode) { case CompSimple: break; @@ -811,14 +808,14 @@ static void paint_all(Display *dpy, XserverRegion region) wComposerSetEventIgnore(dpy, NextRequest(dpy)); if (w->opacity != OPAQUE && !w->shadowPict) w->shadowPict = create_solid_picture(dpy, True, (double)w->opacity / OPAQUE * 0.3, 0, 0, 0); - XRenderComposite(dpy, PictOpOver, w->shadowPict ? w->shadowPict : transBlackPicture, - w->picture, rootBuffer, 0, 0, 0, 0, w->a.x + w->shadow_dx, + XRenderComposite(dpy, PictOpOver, w->shadowPict ? w->shadowPict : trans_black_picture, + w->picture, root_picture_buffer, 0, 0, 0, 0, w->a.x + w->shadow_dx, w->a.y + w->shadow_dy, w->shadow_width, w->shadow_height); break; case CompClientShadows: /* don't bother drawing shadows on desktop windows */ if (w->shadow && w->windowType != winDesktopAtom) { - XRenderComposite(dpy, PictOpOver, blackPicture, w->shadow, rootBuffer, 0, 0, 0, 0, + XRenderComposite(dpy, PictOpOver, black_picture, w->shadow, root_picture_buffer, 0, 0, 0, 0, w->a.x + w->shadow_dx, w->a.y + w->shadow_dy, w->shadow_width, w->shadow_height); } @@ -830,33 +827,33 @@ static void paint_all(Display *dpy, XserverRegion region) if (w->mode == WINDOW_TRANS) { int x, y, wid, hei; XFixesIntersectRegion(dpy, w->borderClip, w->borderClip, w->borderSize); - XFixesSetPictureClipRegion(dpy, rootBuffer, 0, 0, w->borderClip); + XFixesSetPictureClipRegion(dpy, root_picture_buffer, 0, 0, w->borderClip); x = w->a.x; y = w->a.y; wid = w->a.width + w->a.border_width * 2; hei = w->a.height + w->a.border_width * 2; wComposerSetEventIgnore(dpy, NextRequest(dpy)); - XRenderComposite(dpy, PictOpOver, w->picture, w->alphaPict, rootBuffer, 0, 0, 0, 0, x, y, wid, + XRenderComposite(dpy, PictOpOver, w->picture, w->alphaPict, root_picture_buffer, 0, 0, 0, 0, x, y, wid, hei); } else if (w->mode == WINDOW_ARGB) { int x, y, wid, hei; XFixesIntersectRegion(dpy, w->borderClip, w->borderClip, w->borderSize); - XFixesSetPictureClipRegion(dpy, rootBuffer, 0, 0, w->borderClip); + XFixesSetPictureClipRegion(dpy, root_picture_buffer, 0, 0, w->borderClip); x = w->a.x; y = w->a.y; wid = w->a.width + w->a.border_width * 2; hei = w->a.height + w->a.border_width * 2; wComposerSetEventIgnore(dpy, NextRequest(dpy)); - XRenderComposite(dpy, PictOpOver, w->picture, w->alphaPict, rootBuffer, 0, 0, 0, 0, x, y, wid, + XRenderComposite(dpy, PictOpOver, w->picture, w->alphaPict, root_picture_buffer, 0, 0, 0, 0, x, y, wid, hei); } XFixesDestroyRegion(dpy, w->borderClip); w->borderClip = None; } XFixesDestroyRegion(dpy, region); - if (rootBuffer != rootPicture) { - XFixesSetPictureClipRegion(dpy, rootBuffer, 0, 0, None); - XRenderComposite(dpy, PictOpSrc, rootBuffer, None, rootPicture, 0, 0, 0, 0, 0, 0, root_width, + if (root_picture_buffer != root_picture) { + XFixesSetPictureClipRegion(dpy, root_picture_buffer, 0, 0, None); + XRenderComposite(dpy, PictOpSrc, root_picture_buffer, None, root_picture, 0, 0, 0, 0, 0, 0, root_width, root_height); } } @@ -1042,7 +1039,7 @@ static void finish_unmap_window(Display *dpy, CMPWindow *w) w->borderClip = None; } - clipChanged = True; + is_clip_changed = True; } static void unmap_window_callback(Display *dpy, CMPWindow *w, Bool gone) @@ -1101,25 +1098,6 @@ static double get_window_opacity_value(Display *dpy, CMPWindow *w, double def) Future might check for menu flag and other cool things */ -static Atom get_window_type_property(Display *dpy, Window w) -{ - Atom actual; - int format; - unsigned long n, left; - - unsigned char *data; - int result = XGetWindowProperty(dpy, w, winTypeAtom, 0L, 1L, False, XA_ATOM, &actual, &format, &n, - &left, &data); - - if (result == Success && data != (unsigned char *)None) { - Atom a; - memcpy(&a, data, sizeof(Atom)); - XFree((void *)data); - return a; - } - return winNormalAtom; -} - static void determine_mode(Display *dpy, CMPWindow *w) { int mode; @@ -1158,7 +1136,26 @@ static void determine_mode(Display *dpy, CMPWindow *w) } } -static Atom get_window_type(Display *dpy, Window w) +static Atom get_window_type_property(Display *dpy, Window w) +{ + Atom actual; + int format; + unsigned long n, left; + + unsigned char *data; + int result = XGetWindowProperty(dpy, w, winTypeAtom, 0L, 1L, False, XA_ATOM, &actual, &format, &n, + &left, &data); + + if (result == Success && data != (unsigned char *)None) { + Atom a; + memcpy(&a, data, sizeof(Atom)); + XFree((void *)data); + return a; + } + return winNormalAtom; +} + +static Atom get_window_type(Display *dpy, Window window) { Window root_return, parent_return; Window *children = NULL; @@ -1166,10 +1163,11 @@ static Atom get_window_type(Display *dpy, Window w) Atom type; type = get_window_type_property(dpy, w); + if (type != winNormalAtom) return type; - if (!XQueryTree(dpy, w, &root_return, &parent_return, &children, &nchildren)) { + if (!XQueryTree(dpy, window, &root_return, &parent_return, &children, &nchildren)) { /* XQueryTree failed. */ if (children) { XFree((void *)children); @@ -1288,10 +1286,10 @@ static void configure_window(Display *dpy, XConfigureEvent *ce) XserverRegion damage = None; if (!w) { - if (ce->window == root) { - if (rootBuffer) { - XRenderFreePicture(dpy, rootBuffer); - rootBuffer = None; + if (ce->window == root_window) { + if (root_picture_buffer) { + XRenderFreePicture(dpy, root_picture_buffer); + root_picture_buffer = None; } root_width = ce->width; root_height = ce->height; @@ -1338,7 +1336,7 @@ static void configure_window(Display *dpy, XConfigureEvent *ce) w->shape_bounds.height = w->a.height; } - clipChanged = True; + is_clip_changed = True; } static void circulate_windows(Display *dpy, XCirculateEvent *ce) @@ -1355,7 +1353,7 @@ static void circulate_windows(Display *dpy, XCirculateEvent *ce) new_above = None; } restack_window(dpy, w, new_above); - clipChanged = True; + is_clip_changed = True; } static void finish_destroy_window(Display *dpy, Window id, Bool gone) @@ -1539,7 +1537,7 @@ static void wComposerProcessShapeEvent(Display *dpy, XShapeEvent *se) XserverRegion region0; XserverRegion region1; - clipChanged = True; + is_clip_changed = True; region0 = XFixesCreateRegion(dpy, &w->shape_bounds, 1); @@ -1589,7 +1587,7 @@ void wComposerProcessEvent(Display *dpy, XEvent ev) unmap_window(dpy, ev.xunmap.window, True); break; case ReparentNotify: - if (ev.xreparent.parent == root) { + if (ev.xreparent.parent == root_window) { add_window(dpy, ev.xreparent.window, 0); } else { destroy_window(dpy, ev.xreparent.window, False, True); @@ -1599,7 +1597,7 @@ void wComposerProcessEvent(Display *dpy, XEvent ev) circulate_windows(dpy, &ev.xcirculate); break; case Expose: - if (ev.xexpose.window == root) { + if (ev.xexpose.window == root_window) { int more = ev.xexpose.count + 1; if (n_expose == size_expose) { if (expose_rects) { @@ -1623,10 +1621,10 @@ void wComposerProcessEvent(Display *dpy, XEvent ev) break; case PropertyNotify: if (ev.xproperty.atom == XInternAtom(dpy, "_XROOTPMAP_ID", False)) { - if (rootTile) { - XClearArea(dpy, root, 0, 0, 0, 0, True); - XRenderFreePicture(dpy, rootTile); - rootTile = None; + if (root_picture_tile) { + XClearArea(dpy, root_window, 0, 0, 0, 0, True); + XRenderFreePicture(dpy, root_picture_tile); + root_picture_tile = None; break; } } @@ -1709,7 +1707,7 @@ void wComposerRunLoop() paint++; XSync(dpy, False); allDamage = None; - clipChanged = False; + is_clip_changed = False; } } } @@ -1761,7 +1759,7 @@ static Bool wComposerRegister(Display *dpy) static void wComposerAtomsCreate(Display *dpy) { - opacityAtom = XInternAtom(dpy, OPACITY_PROP, False); + opacityAtom = XInternAtom(dpy, "_NET_WM_WINDOW_OPACITY", False); winTypeAtom = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False); winDesktopAtom = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DESKTOP", False); winDockAtom = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DOCK", False); @@ -1778,16 +1776,16 @@ static Bool wComposerExtensionsCheck(Display *dpy) // int composite_major, composite_minor; if (!XRenderQueryExtension(dpy, &render_event, &render_error)) { - fprintf(stderr, "No render extension\n"); + fprintf(stderr, "No Render extension\n"); return False; } if (!XQueryExtension(dpy, COMPOSITE_NAME, &composite_opcode, &composite_event, &composite_error)) { - fprintf(stderr, "No composite extension\n"); + fprintf(stderr, "No Composite extension\n"); return False; } // XCompositeQueryVersion(dpy, &composite_major, &composite_minor); - hasNamePixmap = True; + has_name_pixmap = True; if (!XDamageQueryExtension(dpy, &damage_event, &damage_error)) { fprintf(stderr, "No Damage extension\n"); return False; @@ -1886,11 +1884,11 @@ Bool wComposerInitialize() XSetErrorHandler(wComposerErrorHandler); - if (synchronize) { + if (should_synchronize) { XSynchronize(dpy, 1); } scr = DefaultScreen(dpy); - root = RootWindow(dpy, scr); + root_window = RootWindow(dpy, scr); if (wComposerExtensionsCheck(dpy) == False) { return False; @@ -1912,24 +1910,24 @@ Bool wComposerInitialize() root_width = DisplayWidth(dpy, scr); root_height = DisplayHeight(dpy, scr); - rootPicture = XRenderCreatePicture( - dpy, root, XRenderFindVisualFormat(dpy, DefaultVisual(dpy, scr)), CPSubwindowMode, &pa); - blackPicture = create_solid_picture(dpy, True, 1, 0, 0, 0); + root_picture = XRenderCreatePicture( + dpy, root_window, XRenderFindVisualFormat(dpy, DefaultVisual(dpy, scr)), CPSubwindowMode, &pa); + black_picture = create_solid_picture(dpy, True, 1, 0, 0, 0); if (compMode == CompServerShadows) { - transBlackPicture = create_solid_picture(dpy, True, 0.3, 0, 0, 0); + trans_black_picture = create_solid_picture(dpy, True, 0.3, 0, 0, 0); } allDamage = None; - clipChanged = True; + is_clip_changed = True; XGrabServer(dpy); if (autoRedirect) { - XCompositeRedirectSubwindows(dpy, root, CompositeRedirectAutomatic); + XCompositeRedirectSubwindows(dpy, root_window, CompositeRedirectAutomatic); } else { - XCompositeRedirectSubwindows(dpy, root, CompositeRedirectManual); - XSelectInput(dpy, root, + XCompositeRedirectSubwindows(dpy, root_window, CompositeRedirectManual); + XSelectInput(dpy, root_window, SubstructureNotifyMask | ExposureMask | StructureNotifyMask | PropertyChangeMask); - XShapeSelectInput(dpy, root, ShapeNotifyMask); - XQueryTree(dpy, root, &root_return, &parent_return, &children, &nchildren); + XShapeSelectInput(dpy, root_window, ShapeNotifyMask); + XQueryTree(dpy, root_window, &root_return, &parent_return, &children, &nchildren); for (unsigned int i = 0; i < nchildren; i++) add_window(dpy, children[i], i ? children[i - 1] : None); XFree(children); From 808f9f3275fb389579cd1102bb2f1c8b368998f2 Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Mon, 16 Oct 2023 22:40:14 +0300 Subject: [PATCH 20/67] fixed var name after rename. --- Applications/Workspace/WM/wmcomposer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Applications/Workspace/WM/wmcomposer.c b/Applications/Workspace/WM/wmcomposer.c index c14e99a18..4b3b3046c 100644 --- a/Applications/Workspace/WM/wmcomposer.c +++ b/Applications/Workspace/WM/wmcomposer.c @@ -1162,7 +1162,7 @@ static Atom get_window_type(Display *dpy, Window window) unsigned int nchildren; Atom type; - type = get_window_type_property(dpy, w); + type = get_window_type_property(dpy, window); if (type != winNormalAtom) return type; From 7b88f17c9803633e0c9cf5f1088ae228c9267153 Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Tue, 17 Oct 2023 12:07:00 +0300 Subject: [PATCH 21/67] fix local variable name --- Applications/Workspace/WM/wmcomposer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Applications/Workspace/WM/wmcomposer.c b/Applications/Workspace/WM/wmcomposer.c index c14e99a18..4b3b3046c 100644 --- a/Applications/Workspace/WM/wmcomposer.c +++ b/Applications/Workspace/WM/wmcomposer.c @@ -1162,7 +1162,7 @@ static Atom get_window_type(Display *dpy, Window window) unsigned int nchildren; Atom type; - type = get_window_type_property(dpy, w); + type = get_window_type_property(dpy, window); if (type != winNormalAtom) return type; From 0612ca6104e5e8836edb2b8ccb63f94faa6d9bbb Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Tue, 17 Oct 2023 12:07:22 +0300 Subject: [PATCH 22/67] don't send CF notification for GNUstep app --- Applications/Workspace/WM/application.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Applications/Workspace/WM/application.c b/Applications/Workspace/WM/application.c index c5a31a330..f36013962 100644 --- a/Applications/Workspace/WM/application.c +++ b/Applications/Workspace/WM/application.c @@ -431,8 +431,10 @@ void wApplicationDestroy(WApplication *wapp) scr = wapp->main_wwin->screen; // Notify Workspace's ProcessManager - CFNotificationCenterPostNotification(scr->notificationCenter, WMDidDestroyApplicationNotification, - wapp, NULL, TRUE); + if (!wapp->flags.is_gnustep) { + CFNotificationCenterPostNotification(scr->notificationCenter, + WMDidDestroyApplicationNotification, wapp, NULL, TRUE); + } if (wapp == scr->wapp_list) { if (wapp->next) From 40091a04346231bbfacdfb4463492d52c41bbf79 Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Tue, 17 Oct 2023 12:34:42 +0300 Subject: [PATCH 23/67] don't create launching icon for buggy applications without icons --- Applications/Workspace/WM/appicon.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Applications/Workspace/WM/appicon.c b/Applications/Workspace/WM/appicon.c index c1396e5ec..23f25f3ae 100644 --- a/Applications/Workspace/WM/appicon.c +++ b/Applications/Workspace/WM/appicon.c @@ -1171,8 +1171,8 @@ WAppIcon *wLaunchingAppIconCreate(const char *wm_instance, const char *wm_class, WAppIcon *app_icon = NULL; Window icon_window; - if (wm_instance == NULL || wm_class == NULL) { - // Can't create launching icon without application name + if (wm_instance == NULL || wm_class == NULL || image_path == NULL) { + // Can't create launching icon without application name and icon path return NULL; } From 22176d333a1bdbc6f01d9ffccbec1216686b8812 Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Tue, 17 Oct 2023 12:34:54 +0300 Subject: [PATCH 24/67] handle case with application without NSIcon specified. --- .../Workspace/Controller+NSWorkspace.m | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/Applications/Workspace/Controller+NSWorkspace.m b/Applications/Workspace/Controller+NSWorkspace.m index 5abdc1743..fb9a93ca3 100644 --- a/Applications/Workspace/Controller+NSWorkspace.m +++ b/Applications/Workspace/Controller+NSWorkspace.m @@ -36,6 +36,8 @@ #include #import +#include "Foundation/NSBundle.h" +#include "AppKit/NSImage.h" #import #import @@ -322,7 +324,8 @@ - (BOOL)openFile:(NSString *)fullPath NSString *wmName; NSBundle *appBundle; NSDictionary *appInfo; - NSString *iconPath; + NSString *iconName = nil; + NSString *iconPath = nil; NSString *launchPath; // Don't launch ourself and Login panel @@ -356,7 +359,18 @@ - (BOOL)openFile:(NSString *)fullPath nil, nil, nil, appName, fullPath); return NO; } - iconPath = [appBundle pathForImageResource:[appInfo objectForKey:@"NSIcon"]]; + + if ((iconName = appInfo[@"NSIcon"]) != nil) { + iconPath = [appBundle pathForImageResource:[appInfo objectForKey:@"NSIcon"]]; + if (iconPath == nil) { + NSLog(@"No icon for application found in app bundle!"); + } + } else { + iconName = @"NXUnknownApplication"; + } + if (iconPath == nil) { + iconPath = [[NSBundle mainBundle] pathForImageResource:iconName]; + } [raceLock lock]; wLaunchingAppIconCreate([[wmName stringByDeletingPathExtension] cString], "GNUstep", From f733e15b59964758d9d5be9b21a637561c10b7f2 Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Tue, 17 Oct 2023 16:17:10 +0300 Subject: [PATCH 25/67] rename _workspaceCenter to _windowManagerCenter to omit confusion with internal NSWorkspace notification center. --- .../Workspace/Controller+NSWorkspace.m | 56 ++++++++----------- Applications/Workspace/Controller.h | 2 +- Applications/Workspace/Controller.m | 16 +++--- Applications/Workspace/WMNotificationCenter.m | 12 ++-- 4 files changed, 39 insertions(+), 47 deletions(-) diff --git a/Applications/Workspace/Controller+NSWorkspace.m b/Applications/Workspace/Controller+NSWorkspace.m index fb9a93ca3..8c326b449 100644 --- a/Applications/Workspace/Controller+NSWorkspace.m +++ b/Applications/Workspace/Controller+NSWorkspace.m @@ -168,10 +168,6 @@ - (id)initNSWorkspace if (_applications == nil) { [self findApplications]; } - // [_workspaceCenter addObserver:self - // selector:@selector(_workspacePreferencesChanged:) - // name:GSWorkspacePreferencesChanged - // object:nil]; /* icon association and caching */ folderPathIconDict = [[NSMutableDictionary alloc] initWithCapacity:5]; @@ -856,7 +852,7 @@ - (NSArray *)mountedRemovableMedia - (NSNotificationCenter *)notificationCenter { - return _workspaceCenter; + return _windowManagerCenter; } //------------------------------------------------------------------------------------------------- @@ -1219,31 +1215,25 @@ - (BOOL)_extension:(NSString *)ext role:(NSString *)role app:(NSString **)app // * TODO add a user info to aNotification, which includes a bitmask // * denoting the updated preference files. // */ -// NSFileManager *mgr = [NSFileManager defaultManager]; -// NSData *data; -// NSDictionary *dict; - -// if ([mgr isReadableFileAtPath: extPrefPath] == YES) -// { -// data = [NSData dataWithContentsOfFile: extPrefPath]; -// if (data) -// { -// dict = [NSDeserializer deserializePropertyListFromData: data -// mutableContainers: NO]; -// ASSIGN(extPreferences, dict); -// } +// NSFileManager *mgr = [NSFileManager defaultManager]; +// NSData *data; +// NSDictionary *dict; + +// if ([mgr isReadableFileAtPath:extPrefPath] == YES) { +// data = [NSData dataWithContentsOfFile:extPrefPath]; +// if (data) { +// dict = [NSDeserializer deserializePropertyListFromData:data mutableContainers:NO]; +// ASSIGN(extPreferences, dict); // } +// } -// if ([mgr isReadableFileAtPath: appListPath] == YES) -// { -// data = [NSData dataWithContentsOfFile: appListPath]; -// if (data) -// { -// dict = [NSDeserializer deserializePropertyListFromData: data -// mutableContainers: NO]; -// ASSIGN(applications, dict); -// } +// if ([mgr isReadableFileAtPath:appListPath] == YES) { +// data = [NSData dataWithContentsOfFile:appListPath]; +// if (data) { +// dict = [NSDeserializer deserializePropertyListFromData:data mutableContainers:NO]; +// ASSIGN(applications, dict); // } +// } // /* // * Invalidate the cache of icons for file extensions. // */ @@ -1306,7 +1296,7 @@ - (BOOL)_launchApplication:(NSString *)appName arguments:(NSArray *)args @"NSApplicationPath" : appName }; NSLog(@"Application UserInfo: %@", userinfo); - [_workspaceCenter postNotificationName:NSWorkspaceWillLaunchApplicationNotification + [_windowManagerCenter postNotificationName:NSWorkspaceWillLaunchApplicationNotification object:self userInfo:userinfo]; task = [NSTask launchedTaskWithLaunchPath:path arguments:args]; @@ -1342,7 +1332,7 @@ - (void)_launchedApplicationDidTerminate:(NSNotification *)aNotif if (appicon) { wLaunchingAppIconDestroy(wDefaultScreen(), appicon); } - [_workspaceCenter + [_windowManagerCenter postNotificationName:NSWorkspaceDidTerminateApplicationNotification object:self userInfo:@{@"NSApplicationName" : [[task launchPath] lastPathComponent]}]; @@ -1672,10 +1662,10 @@ - (void)_setBestApp:(NSString *)appName inRole:(NSString *)role forExtension:(NS _extPreferences = map; data = [NSSerializer serializePropertyList:_extPreferences]; if ([data writeToFile:_extPrefPath atomically:YES]) { - // [_workspaceCenter postNotificationName:GSWorkspacePreferencesChanged + // [NSNotificationCenter defaultCenter] postNotificationName:GSWorkspacePreferencesChanged // object:self]; } else { - NSLog(@"Update %@ of failed", _extPrefPath); + NSDebugLLog(@"Workspace", @"Update %@ of failed", _extPrefPath); } } @@ -1711,10 +1701,10 @@ - (void)_setBestIcon:(NSString *)iconPath forExtension:(NSString *)ext _extPreferences = map; data = [NSSerializer serializePropertyList:_extPreferences]; if ([data writeToFile:_extPrefPath atomically:YES]) { - // [_workspaceCenter postNotificationName:GSWorkspacePreferencesChanged + // [NSNotificationCenter defaultCenter] postNotificationName:GSWorkspacePreferencesChanged // object:self]; } else { - NSLog(@"Update %@ of failed", _extPrefPath); + NSDebugLLog(@"Workspace", @"Update %@ of failed", _extPrefPath); } } diff --git a/Applications/Workspace/Controller.h b/Applications/Workspace/Controller.h index abedf7ab8..fe845d408 100644 --- a/Applications/Workspace/Controller.h +++ b/Applications/Workspace/Controller.h @@ -83,7 +83,7 @@ NSMutableDictionary *_iconMap; NSMutableDictionary *_launched; NSArray *_wrappers; - NSNotificationCenter *_workspaceCenter; + NSNotificationCenter *_windowManagerCenter; BOOL _fileSystemChanged; BOOL _userDefaultsChanged; // ~/Library/Services/.GNUstepAppList diff --git a/Applications/Workspace/Controller.m b/Applications/Workspace/Controller.m index 269b5777a..98c0398f7 100644 --- a/Applications/Workspace/Controller.m +++ b/Applications/Workspace/Controller.m @@ -21,7 +21,6 @@ #import #import #import -#include "Foundation/NSNotification.h" #import #import @@ -390,7 +389,7 @@ - (void)_finishTerminateProcess // We don't need to handle events on quit. [[NSNotificationCenter defaultCenter] removeObserver:self]; // Not need to remove observers explicitely for NSWorkspaceCenter. - [_workspaceCenter release]; + [_windowManagerCenter release]; // Close and save file viewers, close panels. [self _saveWindowsStateAndClose]; @@ -626,14 +625,14 @@ - (void)applicationWillFinishLaunching:(NSNotification *)notif [self updateKeyboardBadge:nil]; // Workspace Notification Central - _workspaceCenter = [WMNotificationCenter defaultCenter]; + _windowManagerCenter = [WMNotificationCenter defaultCenter]; // Window Manager events - [_workspaceCenter addObserver:self + [_windowManagerCenter addObserver:self selector:@selector(updateWorkspaceBadge:) name:CF_NOTIFICATION(WMDidChangeDesktopNotification) object:nil]; - [_workspaceCenter addObserver:self + [_windowManagerCenter addObserver:self selector:@selector(updateKeyboardBadge:) name:CF_NOTIFICATION(WMDidChangeKeyboardLayoutNotification) object:nil]; @@ -750,6 +749,8 @@ - (void)activateApplication:(NSNotification *)aNotification // Workspace quit. // Log Out and Power Off terminate quitting when some application won't stop, // some removable media won't unmount/eject (optional: think). +#define LogOut NSAlertDefaultReturn +#define PowerOff NSAlertAlternateReturn - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender { NSApplicationTerminateReply terminateReply; @@ -758,7 +759,7 @@ - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sende switch (NXTRunAlertPanel(_(@"Log Out"), _(@"Do you really want to log out?"), _(@"Log out"), _(@"Power off"), _(@"Cancel"))) { - case NSAlertDefaultReturn: // Log Out + case LogOut: { [[NSApp mainMenu] close]; _isQuitting = [procManager terminateAllBGOperations]; @@ -781,7 +782,7 @@ - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sende ws_quit_code = WSLogoutOnQuit; } } break; - case NSAlertAlternateReturn: // Power off + case PowerOff: { [[NSApp mainMenu] close]; _isQuitting = [procManager terminateAllBGOperations]; @@ -800,6 +801,7 @@ - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sende [self _finishTerminateProcess]; terminateReply = NSTerminateNow; ws_quit_code = WSPowerOffOnQuit; + } } break; default: diff --git a/Applications/Workspace/WMNotificationCenter.m b/Applications/Workspace/WMNotificationCenter.m index cc0334e9a..bbd43f1f5 100644 --- a/Applications/Workspace/WMNotificationCenter.m +++ b/Applications/Workspace/WMNotificationCenter.m @@ -61,7 +61,7 @@ @implementation CFObject // Workspace notification center //----------------------------------------------------------------------------- -static WMNotificationCenter *_workspaceCenter = nil; +static WMNotificationCenter *_windowManagerCenter = nil; typedef enum NotificationSource { LocalNC, DistributedNC, CoreFoundationNC } NotificationSource; @@ -103,7 +103,7 @@ static void _handleCFNotification(CFNotificationCenterRef center, void *observer NSDictionary *nsUserInfo = nil; // This is the mirrored notification sent by us - if (object == _workspaceCenter) { + if (object == _windowManagerCenter) { WMLogWarning("_handleCFNotification: Received mirrored notification from CF. Ignoring..."); return; } @@ -119,7 +119,7 @@ static void _handleCFNotification(CFNotificationCenterRef center, void *observer WMLogWarning("[WMNC] _handleCFNotificaition: dispatching CF notification %@ - %@", name, userInfo); - [_workspaceCenter postNotificationName:nsName object:nsObject userInfo:nsUserInfo]; + [_windowManagerCenter postNotificationName:nsName object:nsObject userInfo:nsUserInfo]; [nsObject release]; [nsUserInfo release]; @@ -168,10 +168,10 @@ @implementation WMNotificationCenter + (instancetype)defaultCenter { - if (!_workspaceCenter) { + if (!_windowManagerCenter) { [[WMNotificationCenter alloc] init]; } - return _workspaceCenter; + return _windowManagerCenter; } - (void)dealloc @@ -190,7 +190,7 @@ - (id)init self = [super init]; if (self != nil) { - _workspaceCenter = self; + _windowManagerCenter = self; _remoteCenter = [[NSDistributedNotificationCenter defaultCenter] retain]; @try { From b51b8aee227fbbbf2784f0f22b88f2cc02fde8a1 Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Tue, 17 Oct 2023 19:01:18 +0300 Subject: [PATCH 26/67] start Composer only if enabled in Workspace defaults. --- Applications/Workspace/Workspace_main.m | 36 ++++++++++++++----------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/Applications/Workspace/Workspace_main.m b/Applications/Workspace/Workspace_main.m index dd959d397..a78ec09ee 100644 --- a/Applications/Workspace/Workspace_main.m +++ b/Applications/Workspace/Workspace_main.m @@ -23,6 +23,7 @@ #import #import +#import #import "Application.h" #import "Recycler.h" @@ -125,9 +126,6 @@ int WSApplicationMain(int argc, const char **argv) int main(int argc, const char **argv) { - dispatch_queue_t composer_q; - dispatch_queue_t window_manager_q; - if (_isWindowServerReady() == NO) { fprintf(stderr, "[Workspace] X Window server is not ready on display '%s'\n", getenv("DISPLAY")); @@ -142,9 +140,9 @@ int main(int argc, const char **argv) fprintf(stderr, "=== Starting Workspace ===\n"); workspace_q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0); { - composer_q = dispatch_queue_create("ns.workspace.composer", DISPATCH_QUEUE_CONCURRENT); + // DISPATCH_QUEUE_CONCURRENT is mandatory for CFRunLoop run. - window_manager_q = dispatch_queue_create("ns.workspace.wm", DISPATCH_QUEUE_CONCURRENT); + dispatch_queue_t window_manager_q = dispatch_queue_create("ns.workspace.wm", DISPATCH_QUEUE_CONCURRENT); //--- Initialize Window Manager fprintf(stderr, "=== Initializing Window Manager ===\n"); @@ -161,17 +159,23 @@ int main(int argc, const char **argv) }); fprintf(stderr, "=== Window Manager initialized! ===\n"); - //--- Start Composer - dispatch_async(composer_q, ^{ - fprintf(stderr, "=== Initializing Composer ===\n"); - if (wComposerInitialize() == True) { - fprintf(stderr, "=== Composer initialized ===\n"); - wComposerRunLoop(); - fprintf(stderr, "=== Composer completed it's execution ===\n"); - } else { - fprintf(stderr, "=== Failed to initialize Composer ===\n"); - } - }); + //--- Composer + NXTDefaults *defs = [[NXTDefaults alloc] initDefaultsWithPath:NSUserDomainMask + domain:@"Workspace"]; + if ([defs boolForKey:@"ComposerEnabled"] != NO) { + dispatch_queue_t composer_q = dispatch_queue_create("ns.workspace.composer", DISPATCH_QUEUE_CONCURRENT); + dispatch_async(composer_q, ^{ + fprintf(stderr, "=== Initializing Composer ===\n"); + if (wComposerInitialize() == True) { + fprintf(stderr, "=== Composer initialized ===\n"); + wComposerRunLoop(); + fprintf(stderr, "=== Composer completed it's execution ===\n"); + } else { + fprintf(stderr, "=== Failed to initialize Composer ===\n"); + } + }); + } + [defs release]; // Start WM run loop V0 to catch events while V1 is warming up. dispatch_async(window_manager_q, ^{ From 21aa39a8cc3724b5cfa450d6e8bbfb0115ad69c2 Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Tue, 17 Oct 2023 19:01:52 +0300 Subject: [PATCH 27/67] name internal compositor as "Workspace Composer" to indicate it's source. --- Applications/Workspace/WM/wmcomposer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Applications/Workspace/WM/wmcomposer.c b/Applications/Workspace/WM/wmcomposer.c index 4b3b3046c..7dd27b508 100644 --- a/Applications/Workspace/WM/wmcomposer.c +++ b/Applications/Workspace/WM/wmcomposer.c @@ -1750,7 +1750,7 @@ static Bool wComposerRegister(Display *dpy) window = XCreateSimpleWindow(dpy, RootWindow(dpy, scr), 0, 0, 1, 1, 0, None, None); - Xutf8SetWMProperties(dpy, window, "Composer", "xcompmgr", NULL, 0, NULL, NULL, NULL); + Xutf8SetWMProperties(dpy, window, "Workspace Composer", "xcompmgr", NULL, 0, NULL, NULL, NULL); XSetSelectionOwner(dpy, atom, window, 0); From c332d2489622a1f2ab2ab6979eaf6cd1a18aaf0b Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Tue, 17 Oct 2023 19:03:00 +0300 Subject: [PATCH 28/67] enable "superfluous" by default - many basic features check if it's enabled. --- Applications/Workspace/WM/defaults.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Applications/Workspace/WM/defaults.c b/Applications/Workspace/WM/defaults.c index 0b34fc2e1..20cf5bc31 100644 --- a/Applications/Workspace/WM/defaults.c +++ b/Applications/Workspace/WM/defaults.c @@ -355,7 +355,7 @@ WDefaultEntry optionList[] = { {"AutoFocus", "YES", NULL, &wPreferences.auto_focus, getBool, NULL, NULL, NULL}, {"RaiseDelay", "0", NULL, &wPreferences.raise_delay, getInt, NULL, NULL, NULL}, {"CirculateRaise", "YES", NULL, &wPreferences.circ_raise, getBool, NULL, NULL, NULL}, - {"Superfluous", "NO", NULL, &wPreferences.superfluous, getBool, NULL, NULL, NULL}, + {"Superfluous", "YES", NULL, &wPreferences.superfluous, getBool, NULL, NULL, NULL}, {"StickyIcons", "YES", NULL, &wPreferences.sticky_icons, getBool, setStickyIcons, NULL, NULL}, {"SaveSessionOnExit", "NO", NULL, &wPreferences.save_session_on_exit, getBool, NULL, NULL, NULL}, {"ScrollableMenus", "YES", NULL, &wPreferences.scrollable_menus, getBool, NULL, NULL, NULL}, From 67c9bb5f3b99e64da0a9b74d8a7c1eea711a3e6c Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Wed, 18 Oct 2023 02:51:11 +0300 Subject: [PATCH 29/67] make main application menu window type to _NET_WM_WINDOW_TYPE_TOOLBAR. --- Applications/Workspace/WM/wmspec.c | 6 ++++++ Libraries/gnustep/back-art/Source/x11/XGServerWindow.m | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Applications/Workspace/WM/wmspec.c b/Applications/Workspace/WM/wmspec.c index 2bc2d90ff..5049ec244 100644 --- a/Applications/Workspace/WM/wmspec.c +++ b/Applications/Workspace/WM/wmspec.c @@ -40,6 +40,7 @@ #include #include +#include "AppKit/NSWindow.h" #include "WM.h" #include "window.h" #include "screen.h" @@ -1089,7 +1090,9 @@ static int getWindowLayer(WWindow *wwin) } else if (wwin->type == net_wm_window_type_menu) { layer = NSSubmenuWindowLevel; } else if (wwin->type == net_wm_window_type_utility) { + layer = NSFloatingWindowLevel; } else if (wwin->type == net_wm_window_type_splash) { + layer = NSPopUpMenuWindowLevel; } else if (wwin->type == net_wm_window_type_dialog) { if (wwin->transient_for) { WWindow *parent = wWindowFor(wwin->transient_for); @@ -1107,7 +1110,9 @@ static int getWindowLayer(WWindow *wwin) } else if (wwin->type == net_wm_window_type_combo) { layer = NSSubmenuWindowLevel; } else if (wwin->type == net_wm_window_type_dnd) { + layer = NSPopUpMenuWindowLevel; } else if (wwin->type == net_wm_window_type_normal) { + layer = NSNormalWindowLevel; } if (wwin->client_flags.sunken && NSSunkenWindowLevel < layer) @@ -1280,6 +1285,7 @@ static Bool _getAttributesForWindowType(Atom type, WWindowAttributes *window_att window_attrs->no_miniaturizable = 1; window_attrs->no_resizebar = 1; window_attrs->no_shadeable = 1; + window_attrs->omnipresent = 1; window_attrs->skip_window_list = 1; window_attrs->skip_switchpanel = 1; window_attrs->dont_move_off = 1; diff --git a/Libraries/gnustep/back-art/Source/x11/XGServerWindow.m b/Libraries/gnustep/back-art/Source/x11/XGServerWindow.m index abd6c156b..3550da1cb 100644 --- a/Libraries/gnustep/back-art/Source/x11/XGServerWindow.m +++ b/Libraries/gnustep/back-art/Source/x11/XGServerWindow.m @@ -2906,7 +2906,7 @@ - (void)setwindowlevel:(int)level :(int)win { data[0] = generic._NET_WM_WINDOW_TYPE_NORMAL_ATOM; skipTaskbar = YES; } else if (level == NSMainMenuWindowLevel) { - data[0] = generic._NET_WM_WINDOW_TYPE_DOCK_ATOM; + data[0] = generic._NET_WM_WINDOW_TYPE_TOOLBAR_ATOM; skipTaskbar = YES; } else if (level == NSSubmenuWindowLevel || level == NSTornOffMenuWindowLevel) { From 028b3db33038a5bdfa1be21c22fb5f950dacf898 Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Wed, 18 Oct 2023 02:52:02 +0300 Subject: [PATCH 30/67] EWMH window type names were added to comments as a references between EWMH and WM window levels. --- Applications/Workspace/WM/GNUstep.h | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/Applications/Workspace/WM/GNUstep.h b/Applications/Workspace/WM/GNUstep.h index ad5494010..c88897b3c 100644 --- a/Applications/Workspace/WM/GNUstep.h +++ b/Applications/Workspace/WM/GNUstep.h @@ -39,24 +39,24 @@ enum { #ifndef __Foundation_h_GNUSTEP_BASE_INCLUDE /* - * Window levels are taken from GNUstep (gui/AppKit/NSWindow.h) + * Window level names are taken from GNUstep (gui/AppKit/NSWindow.h) * Applications are actually permitted to use any value in the * range INT_MIN+1 to INT_MAX */ enum { - // // OPENSTEP // MacOS // GNUstep - NSDesktopWindowLevel = -1000, // ---- // 2 // -1000 - NSSunkenWindowLevel = -1, // ---- // ---- // ---- - NSNormalWindowLevel = 0, // 0 // 3 // 0 - NSFloatingWindowLevel = 3, // 3 // 4 // 2 - NSDockWindowLevel = 5, // 5 // 6 // 21 - NSSubmenuWindowLevel = 10, // 10 // 5 // 3 - NSTornOffMenuWindowLevel = 10, // ---- // 5 // 3 - NSMainMenuWindowLevel = 20, // 20 // 7 // 20 - NSStatusWindowLevel = 21, // ---- // 8 // 21 - NSModalPanelWindowLevel = 100, // ---- // 9 // 100 - NSPopUpMenuWindowLevel = 101, // ---- // 10 // 101 - NSScreenSaverWindowLevel = 1000 // ---- // 12 // 1000 + // NEXTSPACE // OPENSTEP // MacOS // GNUstep // EWMH + NSDesktopWindowLevel = -1000, // -------- // 2 // -1000 _NET_WM_WINDOW_TYPE_DESKTOP + NSSunkenWindowLevel = -1, // -------- // ----- // ------- ------- + NSNormalWindowLevel = 0, // 0 // 3 // 0 _NET_WM_WINDOW_TYPE_NORMAL + NSFloatingWindowLevel = 3, // 3 // 4 // 2 _NET_WM_WINDOW_TYPE_UTILITY + NSDockWindowLevel = 5, // 5 // 6 // 21 _NET_WM_WINDOW_TYPE_DOCK + NSSubmenuWindowLevel = 10, // 10 // 5 // 3 _NET_WM_WINDOW_TYPE_MENU + NSTornOffMenuWindowLevel = 10, // -------- // 5 // 3 _NET_WM_WINDOW_TYPE_MENU + NSMainMenuWindowLevel = 20, // 20 // 7 // 20 _NET_WM_WINDOW_TYPE_TOOLBAR + NSStatusWindowLevel = 21, // -------- // 8 // 21 _NET_WM_WINDOW_TYPE_DOCK + NSModalPanelWindowLevel = 100, // -------- // 9 // 100 _NET_WM_WINDOW_TYPE_NORMAL (!) + NSPopUpMenuWindowLevel = 101, // -------- // 10 // 101 _NET_WM_WINDOW_TYPE_TOOLTIP or _DIALOG + NSScreenSaverWindowLevel = 1000 // -------- // 12 // 1000 ------- }; /* typedef NSUInteger NSWindowStyleMask; */ enum { From d2ccbf18484125e5efaf73f90167c60ce33e3506 Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Wed, 18 Oct 2023 16:58:42 +0300 Subject: [PATCH 31/67] fixed window level of Recycler icon. --- Applications/Workspace/Recycler.m | 1 + 1 file changed, 1 insertion(+) diff --git a/Applications/Workspace/Recycler.m b/Applications/Workspace/Recycler.m index a63d878ce..32ae48e20 100644 --- a/Applications/Workspace/Recycler.m +++ b/Applications/Workspace/Recycler.m @@ -218,6 +218,7 @@ - (id)initWithDock:(WDock *)dock } _appIcon = [[RecyclerIcon alloc] initWithWindowRef:&_dockIcon->icon->core->window recycler:self]; + [_appIcon setLevel:NSDockWindowLevel]; appIconView = [[RecyclerIconView alloc] initWithFrame:NSMakeRect(0, 0, 64, 64)]; [_appIcon setContentView:appIconView]; From 1152f515b85704bd7aac9c7abf4f1d460701d7a1 Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Wed, 18 Oct 2023 16:59:15 +0300 Subject: [PATCH 32/67] set to dock_shadow Dock window level. --- Applications/Workspace/WM/screen.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Applications/Workspace/WM/screen.c b/Applications/Workspace/WM/screen.c index b11a85648..a1e51a6d7 100644 --- a/Applications/Workspace/WM/screen.c +++ b/Applications/Workspace/WM/screen.c @@ -624,6 +624,10 @@ static void createInternalWindows(WScreen *scr) scr->dock_shadow = XCreateWindow(dpy, scr->root_win, 0, 0, wPreferences.icon_size, wPreferences.icon_size, 0, scr->w_depth, CopyFromParent, scr->w_visual, vmask, &attribs); + Atom data = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DOCK", False); + Atom property = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False); + XChangeProperty(dpy, scr->dock_shadow, property, XA_ATOM, 32, PropModeReplace, + (unsigned char *)&data, 1); /* workspace name */ vmask = CWBackPixel | CWSaveUnder | CWOverrideRedirect | CWColormap | CWBorderPixel; From 5179a0c3df84567adbd9807ec636446a89fbc92d Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Thu, 19 Oct 2023 01:12:37 +0300 Subject: [PATCH 33/67] removed automatically inserted include --- Applications/Workspace/WM/wmspec.c | 1 - 1 file changed, 1 deletion(-) diff --git a/Applications/Workspace/WM/wmspec.c b/Applications/Workspace/WM/wmspec.c index 5049ec244..9846c19dd 100644 --- a/Applications/Workspace/WM/wmspec.c +++ b/Applications/Workspace/WM/wmspec.c @@ -40,7 +40,6 @@ #include #include -#include "AppKit/NSWindow.h" #include "WM.h" #include "window.h" #include "screen.h" From 5f273d941a00295db830e00fbacb182fd32a7815 Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Thu, 19 Oct 2023 12:06:59 +0300 Subject: [PATCH 34/67] fixed font name in controls. --- .../English.lproj/FileMoverUI.gorm/data.info | Bin 184 -> 184 bytes .../FileMoverUI.gorm/objects.gorm | Bin 5509 -> 5958 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/Applications/Workspace/Processes/English.lproj/FileMoverUI.gorm/data.info b/Applications/Workspace/Processes/English.lproj/FileMoverUI.gorm/data.info index 744f736ac677af8ec7d5dea09e04106fa43755a2..a97a2a906f0a4e3651d10306d9c0dff5738135af 100644 GIT binary patch delta 12 TcmdnNxPx&*Dibr~#PmP_8YBa^ delta 12 TcmdnNxPx&*Dif2$#PmP_8hZoH diff --git a/Applications/Workspace/Processes/English.lproj/FileMoverUI.gorm/objects.gorm b/Applications/Workspace/Processes/English.lproj/FileMoverUI.gorm/objects.gorm index a199711a022ab8b8638ce6e3db9b90e6e257d8f2..5e5033f9bdb36cd472edbc16b7718b1db45e94c5 100644 GIT binary patch literal 5958 zcmdT|TX)+;5MC>ebFrG{YDm+9dm(MOj!L-&XcUL0mk=kd)0R6Zwvw1SmXYPAIfugu zPrUG;!vjBpC;1ofz#rhJ@XQl4JJLqja-gT-0M3a#-W~1Ce)G-l>|QV4ZF+ViZ@J~2 z>O&gh0`n-~$EbwD8*haIU{}gWiIMB2Vs&%Lse4wnZo5JV&CtYPv9z}NrCs*$ zw-BHieL^pmR$HF6S+h&FY&O!OzgP-?h*{K2L7&ktMz5FdSL+pLZ^Pbg)GW`Y9wS4R zmTFeBS=zH24QUBSP8$PctmL`X`Zg)bfd-#Lad-+JgK1F|C2?O=MO{>cBle6zdVwvV zLZ2}tvc=LJyV-E+6*+85(Cfm_<@AN$ND@Lf&#{ox&4<5+O_c*F+>%c;eKQmUDjnRA zKXmikFQfqd#<0i~OZTew9yUCt3G_scf)6Dmc%ljXOKGXdqjBGdjFA;13i?IYwf1Q! zLl*2y+)rz4>q~)uN)24LPtg9=s9$Bu$`40U?+y! z!zu_o^l=(i2njSi%!UUgT_9_W5Fa+|N8WPPu2s-@$~Y;8iY4N>>(rAz*iStWN&7ozgPrw-CF{W0FFo6aX|^)aqHc6+@uIb zgUJx;nMA0s9Y|o07wXepP@h4lpJAx`6x4m%hBNO6r-El95PN<9=fQn82Ci9PuEu%n zF{S^C$DL{tj~I_>$;@|wdltbx$KcK?aA!4I=4g8eUbsi?5&nwGy%{Wecm0FpKA(vHA-Ow&?Xiz{swLrnp$q@#5dT@m|ANB* z!r#E(a|r#}2<2Yi|9SK;8dFqr7FwR?)RFwL`oY`@lYzf*OV-W1QGUG1LXTi{s&xkA zEGEOHu3*d=IVu#`m#{Rzt?+q{Pg=z%t(82d;lm5O%n$K0|9og9zVoNzafxD~_UYbq z7b;u2h2!4)U*zctKX}pCLUUN9Mc!s20qemmfi54aQ3*U#c&R-_ILTev{0eI#{KTu` z&d5AL0AKD3;4AGM08b~rE3aFvrtJqW1n~b15eDX1Vq+Lj2^~+0t)}PfMyD;~X)z?v zsW-7q!(gQZTxJMmc_nM%5v};a#=7flyLPj=UbQi3W;2YfdH;Z7Ov%aTIxNCMfzPe4 zw#VTLj~L&-@eJj|Yn(x8B;L_~5zYSn+)1b+CE?`*UTx^mGFlOksi*F?BvZR+;8Y~7Y zKHP231h<1lAMT-02yXjuABBaW;KK(fn8AV%AEHns;Ug5TlJGGKw@CN|g*6gBMPZeM z&rrBS!so_mF%{XRTOzzHikn{zR^SVsNPN@AJ*qJeR{J!LvI3i|5Kq7c?dtPTMmy_d zr-H&#u0>mtI%LIc@HSJfMJdB z3J3d2YOR6GT5;}p4*TAeDp$cvQen?qQe_byvPvBKJ$VNWds5>zJnHtQ;W}lk6>yP+ K{q{6%8sZOmV+;oX literal 5509 zcmcIoOLyDG6&^wq^&l0 z-7Hvc<)C(C1Hj(x<=e1=06%&)1n=&K0I({hr_{tNxmZuD;j$Uts9R{4f+2laP2M%1)EZUic-uZ~)-BJb z8a+cjmFiZjWgc72CijFbr}Yu)%=Fw^W1kGUq0yTN$LH`enpS0Hswb+Z8mg)sb*zul z1JVN;4C!MkTQ(ort)|ncaNU5B0T|ho(9Q`LOsy=7%316}6jSwg_ zdNIm3IpeQB0~prFRip3d>%58 zGg^}jbH+Pi(cszZH|w804SmarZ_*!J&?nW!gl{FgPVQ*>6s@kcidS$SRFwhnC{F6uM%>^hDY?S{h6C#8Y0xPdY4 zo?Sn(y;{Yh_A=Qukvd|fl2}v01P_kndCHf3lNb=A#BHRLNHDpy@B6W#79)N{F7aaY zU-&Sk&yw6rPTiphg>+2IXr^d194MwFP?VLW4wa3eqJ+Vsjz1T}M-xjc%7z(vDid>% z(aaMJn};wfH8XL|jOL+)idN<6zU#CbRqh++If!QfI*7_?N>lNrJFi?8$v{Qm74;BI1#=6Uq?LVeQ2#Hs~dGm8E!H-d7R(e$Ei6DPSh5cqc ztb__F)?M%6=jX`J4dLfj%+D>2B2>ZID|iQXp;~h>!*JY_!XC!1Ld9v;>}p{TbxIW8 zIE}ifypOZK+n*S65)!*PkixFS`nfq}5A8P_MB%L-3V(qVE((P=VhV5k2ns!i2waSa zI_jd{YbeQI_VD>D zJx}|r_|e^2-w=w^F~w=k^qeM9_(s@ha??vC=_Jm0`|4Z967c#dRIj-0y(yk4KX}vE zuu05IsKX4;l<#MWAHKv>7di@Wb>?U|y!jYk%f6n>`})cI2^{~rhhymEK^M1^o6nZj zZrQ{ro-Od(!(s2;|CLeX@s+7u)-S0X9$nfk&pC|JfBiKz#s{YjOdgQul!CWq)V%3) zf;OR*Kil4NoqgACwYF+Da%{B1sW6^Ar|F>`>K+3O${`>EQgFL74Zo2VliLd>^*+2K zTX-5ZarXDzxg3z9u*~=Z?{+Xbg7?I0&apT%%cL;_J5ep=VP19!?@K-Flk4Zw>bQHn zQ$^0zo~nJ!+#J>BV_%%h!AhcaW;vtDQ4l_mnq+=UDe(j6$aaGd^0|L~9}!&;fZYH4 zFANd;ktm|M&KiTUd_ZuxjQw^_bpe> zbC)SJ^_KBspMX^vST2rFIW0cjEG{nvSHTdAk=SBHBcU$pOTiedo%J{@1z9Mb#oQ2- zq&k^2qYM}E(Gj>Kb(3+=lU?5^!lDcCF>Yh)Vs|07yMT)$u{M0TE27qd^?{o1MhuR$ zKR)L6rj`i1@LI3#NfRy6`|O zvN5k&Ef)Rb4Jb=>a!ttYN3*vCn`e1|;<*G{2@iO=h04OmhvA`ACMUHUB}shC@aU`_ zZZ8El!4!)DE@A_3!L}@(c{-ua!()AcUWUjEs|F{Jyx4*w>?AxL$dwOIIt#&8Q1sz5 z1f^ihhu>;=lJoI5-zp7@r z!_Br=xAEZF)89_81_#nyQeKs|>)H)@F9NmB)nF&M4_}F0asns?=a(n&l#Mo_KG^6} zYuB#BAsd;{5Tm3Rc>p3gaM#zOeEGtZIae>I^8 AT>t<8 From 108194f06541a1d04a0d52e586e8e366e8f50e03 Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Fri, 20 Oct 2023 13:17:22 +0300 Subject: [PATCH 35/67] removed debug output. --- Frameworks/DesktopKit/NXTDefaults.m | 7 ++++--- Frameworks/DesktopKit/compile_flags.txt | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) create mode 120000 Frameworks/DesktopKit/compile_flags.txt diff --git a/Frameworks/DesktopKit/NXTDefaults.m b/Frameworks/DesktopKit/NXTDefaults.m index 3542774c5..941777930 100644 --- a/Frameworks/DesktopKit/NXTDefaults.m +++ b/Frameworks/DesktopKit/NXTDefaults.m @@ -146,10 +146,11 @@ - (NXTDefaults *)initWithGlobalUserDefaults - (void)dealloc { - NSLog(@"[NXTDefaults] - dealloc"); [self synchronize]; - - if (syncTimer) [syncTimer release]; + + if (syncTimer) { + [syncTimer release]; + } [defaultsDict release]; [filePath release]; [syncLock release]; diff --git a/Frameworks/DesktopKit/compile_flags.txt b/Frameworks/DesktopKit/compile_flags.txt new file mode 120000 index 000000000..7a643aa9f --- /dev/null +++ b/Frameworks/DesktopKit/compile_flags.txt @@ -0,0 +1 @@ +../../compile_flags.txt \ No newline at end of file From 2579f84e82402c4e7c7a7fed221e53b0810af64f Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Fri, 20 Oct 2023 19:02:18 +0300 Subject: [PATCH 36/67] initial implementation of performFileOperation:source:destination:files:tag: --- .../Workspace/Controller+NSWorkspace.m | 38 ++++++++++++++----- .../Workspace/Processes/ProcessManager.h | 2 +- 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/Applications/Workspace/Controller+NSWorkspace.m b/Applications/Workspace/Controller+NSWorkspace.m index 8c326b449..17878b248 100644 --- a/Applications/Workspace/Controller+NSWorkspace.m +++ b/Applications/Workspace/Controller+NSWorkspace.m @@ -428,16 +428,34 @@ - (BOOL)openFile:(NSString *)fullPath //--- Manipulating Files //------------------------------------------------------------------------------------------------- // FIXME: TODO -// - (BOOL)performFileOperation:(NSString*)operation -// source:(NSString*)source -// destination:(NSString*)destination -// files:(NSArray*)files -// tag:(int*)tag -// { -// // FiXME - -// return NO; -// } +- (BOOL)performFileOperation:(NSString*)operation + source:(NSString*)source + destination:(NSString*)destination + files:(NSArray*)files + tag:(int*)tag +{ + OperationType opType = 0; + + if ([operation isEqualToString:@"Copy"]) { + opType = CopyOperation; + } else if ([operation isEqualToString:@"Duplicate"]) { + opType = DuplicateOperation; + } else if ([operation isEqualToString:@"Move"]) { + opType = MoveOperation; + } else if ([operation isEqualToString:@"Link"]) { + opType = LinkOperation; + } else if ([operation isEqualToString:@"Delete"]) { + opType = DeleteOperation; + } else if ([operation isEqualToString:@"Recycle"]) { + opType = RecycleOperation; + } + + if (opType) { + [procManager startOperationWithType:opType source:source target:destination files:files]; + return YES; + } + return NO; +} // From OpenUp: // [[NSWorkspace sharedWorkspace] selectFile:archivePath diff --git a/Applications/Workspace/Processes/ProcessManager.h b/Applications/Workspace/Processes/ProcessManager.h index b6094bee2..13e3723ab 100644 --- a/Applications/Workspace/Processes/ProcessManager.h +++ b/Applications/Workspace/Processes/ProcessManager.h @@ -66,7 +66,7 @@ extern NSString *WMOperationProcessingFileNotification; extern NSString *WMApplicationDidTerminateSubprocessNotification; typedef enum { - CopyOperation, + CopyOperation = 1, DuplicateOperation, MoveOperation, LinkOperation, From 70068505fc5134a6436dc2de20cca997e66e611f Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Fri, 20 Oct 2023 22:51:18 +0300 Subject: [PATCH 37/67] wmcomposer: change shadow defaults. --- Applications/Workspace/WM/wmcomposer.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Applications/Workspace/WM/wmcomposer.c b/Applications/Workspace/WM/wmcomposer.c index 7dd27b508..16fe0f577 100644 --- a/Applications/Workspace/WM/wmcomposer.c +++ b/Applications/Workspace/WM/wmcomposer.c @@ -157,10 +157,10 @@ static int wComposerShouldIgnoreEvent(Display *dpy, unsigned long sequence); static CompMode compMode = CompSimple; -static int shadowRadius = 12; -static int shadowOffsetX = -15; -static int shadowOffsetY = -15; -static double shadowOpacity = .75; +static int shadowRadius = 20; // 12; +static int shadowOffsetX = -30; // -15; +static int shadowOffsetY = -30; // -15; +static double shadowOpacity = .20; //.75; static Bool fadeWindows = False; static Bool fadeTrans = False; From 4ea927955787eab69a9e396727259f95d4f73f63 Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Mon, 23 Oct 2023 15:09:07 +0300 Subject: [PATCH 38/67] use default TrueType interpreter on platform. --- Applications/Login/Login_main.m | 2 +- Applications/Login/UserSession.m | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Applications/Login/Login_main.m b/Applications/Login/Login_main.m index 19cede29b..6d9961c88 100644 --- a/Applications/Login/Login_main.m +++ b/Applications/Login/Login_main.m @@ -349,7 +349,7 @@ int main(int argc, const char **argv) // do window decorations ourselves [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"GSX11HandlesWindowDecorations"]; - setenv("FREETYPE_PROPERTIES", "truetype:interpreter-version=35", 1); + // setenv("FREETYPE_PROPERTIES", "truetype:interpreter-version=35", 1); // Start our application without appicon [LoginApplication sharedApplication]; NSApplicationMain(argc, argv); diff --git a/Applications/Login/UserSession.m b/Applications/Login/UserSession.m index 9f2fe535f..9dca643c0 100644 --- a/Applications/Login/UserSession.m +++ b/Applications/Login/UserSession.m @@ -117,7 +117,7 @@ - (BOOL)_setUserEnvironment setenv("GNUSTEP_PATHLIST", [[NSString stringWithFormat:@"%s:/:/usr/NextSpace:/Network", user->pw_dir] cString], 1); setenv("INFOPATH", [[NSString stringWithFormat:@"%s/Library/Documentation/info:/Library/Documentation/info:/usr/NextSpace/Documentation/info", user->pw_dir] cString], 1); - setenv("FREETYPE_PROPERTIES", "truetype:interpreter-version=35", 1); + // setenv("FREETYPE_PROPERTIES", "truetype:interpreter-version=35", 1); // For developers setenv("GNUSTEP_MAKEFILES", "/Developer/Makefiles", 1); From 0ce5599845dc68179c2932af1920d64e9ab15030 Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Mon, 23 Oct 2023 17:39:47 +0300 Subject: [PATCH 39/67] Prefernces-Font: show example text exactly for selected font. --- Applications/Preferences/Modules/Font/Font.h | 2 -- Applications/Preferences/Modules/Font/Font.m | 31 +++++--------------- 2 files changed, 7 insertions(+), 26 deletions(-) diff --git a/Applications/Preferences/Modules/Font/Font.h b/Applications/Preferences/Modules/Font/Font.h index 5afbce5f1..521025d45 100644 --- a/Applications/Preferences/Modules/Font/Font.h +++ b/Applications/Preferences/Modules/Font/Font.h @@ -46,8 +46,6 @@ NSImage *image; NSString *exampleString; - NSString *normalExampleString; - NSString *boldExampleString; } - (IBAction)fontCategoryChanged:(id)sender; diff --git a/Applications/Preferences/Modules/Font/Font.m b/Applications/Preferences/Modules/Font/Font.m index 675da8554..ad1cc1749 100644 --- a/Applications/Preferences/Modules/Font/Font.m +++ b/Applications/Preferences/Modules/Font/Font.m @@ -212,7 +212,7 @@ notification center (WM should handle this notification and reread file). */ // Convert font name into the FontConfig format. value = [NSMutableString stringWithFormat:@"%@:postscriptname=%@:pixelsize=%.0f:antialias=false", - [font familyName], [font fontName], [font pointSize]]; + [font familyName], [font fontName], [font pointSize]]; NSLog(@"[Font] set WM font %@ = `%@`", key, value); [wmDefaults setObject:value forKey:key]; @@ -224,7 +224,7 @@ - (void)updateUI { NSString *fontKey; NSString *fontSizeKey; - NSFont *font, *boldFont; + NSFont *font; fontKey = [fontCategories objectForKey:[fontCategoryPopUp titleOfSelectedItem]]; @@ -238,21 +238,13 @@ - (void)updateUI fontSizeKey = [NSString stringWithFormat:@"%@Size", fontKey]; font = [NSFont fontWithName:getStringDefault(domain, fontKey) size:getFloatDefault(domain, fontSizeKey)]; - boldFont = [[NSFontManager sharedFontManager] convertFont:font - toHaveTrait:NSBoldFontMask]; - // [fontNameTextField setFont:font]; [fontNameTextField setStringValue:[NSString stringWithFormat: @"%@ %g point", [font displayName], [font pointSize]]]; - // [fontExampleTextView setFont:font]; - [fontExampleTextView setFont:boldFont - range:NSMakeRange([normalExampleString length], - [boldExampleString length]+1)]; - // [enableAntiAliasingButton setIntValue:getBoolDefault(domain, @"GSFontAntiAlias")]; @@ -293,10 +285,10 @@ - (void)dealloc [image release]; [fontCategories dealloc]; - if (view) { - [normalExampleString release]; - [boldExampleString release]; - } + // if (view) { + // [normalExampleString release]; + // [boldExampleString release]; + // } [super dealloc]; } @@ -336,16 +328,7 @@ - (void)awakeFromNib exampleString = NSLocalizedStringFromTableInBundle(@"Example Text", @"Localizable", bundle, @""); - normalExampleString = [[NSString alloc] initWithFormat:@"Normal:\n%@", - exampleString]; - boldExampleString = [[NSString alloc] initWithFormat:@"Bold:\n%@", - exampleString]; - - [fontExampleTextView setText:[NSString stringWithFormat:@"%@\n%@", - normalExampleString, - boldExampleString]]; - // [fontExampleTextView - // readRTFDFromFile:[bundle pathForResource:@"ExampleText" ofType:@"rtf"]]; + [fontExampleTextView setText:exampleString]; [self updateUI]; } From c47a6cd93c997c68d308cf3209dfb2110fb79257 Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Mon, 23 Oct 2023 18:18:57 +0300 Subject: [PATCH 40/67] Preferences-Font: fixed size and name of WM fonts. --- Applications/Preferences/Modules/Font/Font.m | 30 +++++++++++--------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/Applications/Preferences/Modules/Font/Font.m b/Applications/Preferences/Modules/Font/Font.m index ad1cc1749..f4bfffc02 100644 --- a/Applications/Preferences/Modules/Font/Font.m +++ b/Applications/Preferences/Modules/Font/Font.m @@ -186,23 +186,25 @@ static void setIntDefault(int anInt, NSString *name) userDefPath = [NSString stringWithFormat:@"%@/.NextSpace/WM.plist", GSDefaultsRootForUser(NSUserName())]; - if (![[NSFileManager defaultManager] fileExistsAtPath:userDefPath]) { - userDefPath = nil; - } + // if (![[NSFileManager defaultManager] fileExistsAtPath:userDefPath]) { + // userDefPath = nil; + // } return userDefPath; } - (void)setWMFont:(NSFont *)font key:(NSString *)key { - NSString *wmDefaultsPath = WWMDefaultsPath(); + NSString *wmDefaultsPath = WWMDefaultsPath(); NSMutableDictionary *wmDefaults; - NSMutableString *value; + NSMutableString *value; + NSDistributedNotificationCenter *center = nil; if (![[NSFileManager defaultManager] fileExistsAtPath:wmDefaultsPath]) { /* TODO: WM doesn't track WM.plist changes if it doesn't exist. We need to send WMDidChangeWindowAppearanceSettings to the distributed notification center (WM should handle this notification and reread file). */ + center = [NSDistributedNotificationCenter defaultCenter]; NSLog(@"[Font] can't find existing WM defaults database! Creating new..."); wmDefaults = [NSMutableDictionary new]; } @@ -211,13 +213,17 @@ notification center (WM should handle this notification and reread file). */ } // Convert font name into the FontConfig format. - value = [NSMutableString stringWithFormat:@"%@:postscriptname=%@:pixelsize=%.0f:antialias=false", - [font familyName], [font fontName], [font pointSize]]; - NSLog(@"[Font] set WM font %@ = `%@`", key, value); + value = [NSMutableString stringWithFormat:@"%@:postscriptname=%@:pixelsize=%.0f:antialias=%@", + [font familyName], [font fontName], [font pointSize], + [enableAntiAliasingButton state] ? @"true" : @"false"]; + NSLog(@"[Font] set WM font %@ = `%@` -> (%@)", key, value, wmDefaultsPath); [wmDefaults setObject:value forKey:key]; [wmDefaults writeToFile:wmDefaultsPath atomically:YES]; [wmDefaults release]; + if (center != nil) { + [center postNotificationName:@"WMDidChangeWindowAppearanceSettings" object:nil]; + } } - (void)updateUI @@ -423,14 +429,12 @@ - (void)changeFont:(id)sender setStringDefault(fontName, @"NSLabelFont"); setFloatDefault(fontSize, @"NSLabelFontSize"); // NSMiniFontSize=9, NSSmallFontSize=11 - setFloatDefault(fontSize - 4.0, @"NSMiniFontSize"); + setFloatDefault(fontSize - 3.0, @"NSMiniFontSize"); setFloatDefault(fontSize - 2.0, @"NSSmallFontSize"); // WM - [self setWMFont:[NSFont fontWithName:[font familyName] size:fontSize - 4.0] - key:@"IconTitleFont"]; + [self setWMFont:[NSFont fontWithName:fontName size:fontSize - 3.0] key:@"IconTitleFont"]; [self setWMFont:font key:@"MenuTextFont"]; - [self setWMFont:[NSFont fontWithName:[font familyName] size:fontSize * 2.0] - key:@"LargeDisplayFont"]; + [self setWMFont:[NSFont fontWithName:fontName size:fontSize * 2.0] key:@"LargeDisplayFont"]; } else if ([fontKey isEqualToString:@"NSBoldFont"]) { // Bold System // NSBoldFont, NSBoldFontSize=12 From fa6b0f55f80c7437fd1685ec0d05e4a0a69421dd Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Mon, 23 Oct 2023 18:21:42 +0300 Subject: [PATCH 41/67] Preferences: show window if app is not autolaunched. --- Applications/Preferences/AppController.m | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Applications/Preferences/AppController.m b/Applications/Preferences/AppController.m index f31f717b9..5dc9b30ff 100644 --- a/Applications/Preferences/AppController.m +++ b/Applications/Preferences/AppController.m @@ -94,6 +94,8 @@ - (void)applicationDidFinishLaunching:(NSNotification *)aNotif if ([screen savedBackgroundColorRed:&red green:&green blue:&blue] == YES) { [screen setBackgroundColorRed:red green:green blue:blue]; } + } else { + [self showPreferencesWindow]; } } From 18bd7048cac34ae81f55eb0f9ca15938e3c9edc1 Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Mon, 23 Oct 2023 18:45:55 +0300 Subject: [PATCH 42/67] Preferences: show window when becomes active (for example after activation with keyboard shortcut). --- Applications/Preferences/AppController.m | 1 + 1 file changed, 1 insertion(+) diff --git a/Applications/Preferences/AppController.m b/Applications/Preferences/AppController.m index 5dc9b30ff..fd426bc75 100644 --- a/Applications/Preferences/AppController.m +++ b/Applications/Preferences/AppController.m @@ -113,6 +113,7 @@ - (void)applicationWillTerminate:(NSNotification *)aNotif - (void)applicationDidBecomeActive:(NSNotification*)aNotification { + [self showPreferencesWindow]; } - (BOOL)application:(NSApplication *)application openFile:(NSString *)fileName From 473c8e03d2dedf73986a262042d72db35d4242f1 Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Tue, 24 Oct 2023 19:24:56 +0300 Subject: [PATCH 43/67] initial effort to rebirth of the WM.plist defaults file. --- Applications/Workspace/WM/WM.h | 1 + Applications/Workspace/WM/defaults.c | 30 +++++++++++++++++----------- Applications/Workspace/WM/screen.c | 2 +- Applications/Workspace/WM/startup.c | 5 +++++ 4 files changed, 25 insertions(+), 13 deletions(-) diff --git a/Applications/Workspace/WM/WM.h b/Applications/Workspace/WM/WM.h index 6bc0f39a0..eb6d0bb34 100644 --- a/Applications/Workspace/WM/WM.h +++ b/Applications/Workspace/WM/WM.h @@ -242,6 +242,7 @@ extern struct wm_global_variables { struct { /* Note: you must #include if you want to use them */ struct WDDomain *wm; + struct WDDomain *wm_preferences; struct WDDomain *window_attr; struct WDDomain *root_menu; } domain; diff --git a/Applications/Workspace/WM/defaults.c b/Applications/Workspace/WM/defaults.c index 20cf5bc31..879a837b1 100644 --- a/Applications/Workspace/WM/defaults.c +++ b/Applications/Workspace/WM/defaults.c @@ -886,6 +886,10 @@ void wDefaultsReadStatic(CFMutableDictionaryRef dict) } // Apply `plvalue` from `new_dict` to appropriate `entry->addr` specified in `optionList` +// Load wPreferences with values loaded from WM.plist - set default values otherwise. +// +// TODO: Currently `w_global.domain.wm->dictionary` is a memory rep of the WMState.plist file. +// So, this function has no connection to WM.plist file if any exsists. void wDefaultsRead(WScreen *scr, CFMutableDictionaryRef new_dict, Bool shouldNotify) { CFTypeRef plvalue = NULL; @@ -896,8 +900,8 @@ void wDefaultsRead(WScreen *scr, CFMutableDictionaryRef new_dict, Bool shouldNot void *tdata; CFDictionaryRef old_dict = NULL; - if (w_global.domain.wm->dictionary != new_dict) - old_dict = w_global.domain.wm->dictionary; + if (w_global.domain.wm_preferences->dictionary != new_dict) + old_dict = w_global.domain.wm_preferences->dictionary; needs_refresh = 0; @@ -906,15 +910,15 @@ void wDefaultsRead(WScreen *scr, CFMutableDictionaryRef new_dict, Bool shouldNot if (new_dict) { plvalue = CFDictionaryGetValue(new_dict, entry->plkey); - } - else { + if (plvalue) + WMLogWarning("Got value: %@ for %@", plvalue, entry->plkey); + } else { plvalue = NULL; } - + if (!old_dict) { old_value = NULL; - } - else { + } else { old_value = CFDictionaryGetValue(old_dict, entry->plkey); } @@ -922,17 +926,16 @@ void wDefaultsRead(WScreen *scr, CFMutableDictionaryRef new_dict, Bool shouldNot /* WMLogError("Check if default exist: %@", entry->plkey); */ if (plvalue && CFEqual(plvalue, entry->plvalue)) { plvalue = NULL; - /* WMLogError("Removing setting equal to default: %@", entry->plkey); */ + // WMLogError("Removing setting equal to default: %@", entry->plkey); CFDictionaryRemoveValue(new_dict, entry->plkey); - /* WMLogError("Removed"); */ + // WMLogError("Removed"); } if (!plvalue) { /* value was deleted from DB. Keep current value */ plvalue = entry->plvalue; /* continue; */ - } - else if (!old_value) { + } else if (!old_value) { /* set value for the 1st time */ } else if (CFEqual(plvalue, old_value)) { @@ -942,6 +945,7 @@ void wDefaultsRead(WScreen *scr, CFMutableDictionaryRef new_dict, Bool shouldNot if (plvalue) { /* convert data */ + WMLogWarning("Processing %@", entry->plkey); if ((*entry->convert) (scr, entry, plvalue, entry->addr, &tdata)) { if (entry->update) { needs_refresh |= (*entry->update) (scr, entry, tdata, entry->extra_data); @@ -950,7 +954,9 @@ void wDefaultsRead(WScreen *scr, CFMutableDictionaryRef new_dict, Bool shouldNot } } - if (shouldNotify && needs_refresh != 0/* && !scr->flags.startup && !scr->flags.startup2*/) { + WMLogInfo("%@ values: %@ - needs_refresh: %i", w_global.domain.wm_preferences->name, w_global.domain.wm_preferences->dictionary, needs_refresh); + + if (shouldNotify && needs_refresh != 0 /* && !scr->flags.startup && !scr->flags.startup2*/) { int foo; foo = 0; diff --git a/Applications/Workspace/WM/screen.c b/Applications/Workspace/WM/screen.c index a1e51a6d7..64aed8b17 100644 --- a/Applications/Workspace/WM/screen.c +++ b/Applications/Workspace/WM/screen.c @@ -800,7 +800,7 @@ WScreen *wScreenInit(int screen_number) allocGCs(scr); /* read defaults for this screen */ - wDefaultsRead(scr, w_global.domain.wm->dictionary, True); + wDefaultsRead(scr, w_global.domain.wm_preferences->dictionary, True); { XColor xcol; diff --git a/Applications/Workspace/WM/startup.c b/Applications/Workspace/WM/startup.c index 9d0bc50e0..b2ef4fbc0 100644 --- a/Applications/Workspace/WM/startup.c +++ b/Applications/Workspace/WM/startup.c @@ -651,6 +651,11 @@ void wStartUp(Bool defaultScreenOnly) WMHookEventHandler(DispatchEvent); /* initialize defaults stuff */ + w_global.domain.wm_preferences = wDefaultsInitDomain("WM", true); + if (!w_global.domain.wm_preferences->dictionary) { + WMLogWarning(_("could not read domain \"%s\" from defaults database"), "WMState"); + } + w_global.domain.wm = wDefaultsInitDomain("WMState", true); if (!w_global.domain.wm->dictionary) { WMLogWarning(_("could not read domain \"%s\" from defaults database"), "WMState"); From ae63d16262b541115bec6430ff388ed69e30dd32 Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Tue, 24 Oct 2023 19:25:42 +0300 Subject: [PATCH 44/67] Preferences-Font: send notification with object "GSWorkspaceNotification" to be accepted by WMNotificationCenter. --- Applications/Preferences/Modules/Font/Font.m | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Applications/Preferences/Modules/Font/Font.m b/Applications/Preferences/Modules/Font/Font.m index f4bfffc02..73b335155 100644 --- a/Applications/Preferences/Modules/Font/Font.m +++ b/Applications/Preferences/Modules/Font/Font.m @@ -198,13 +198,12 @@ - (void)setWMFont:(NSFont *)font key:(NSString *)key NSString *wmDefaultsPath = WWMDefaultsPath(); NSMutableDictionary *wmDefaults; NSMutableString *value; - NSDistributedNotificationCenter *center = nil; + NSDistributedNotificationCenter *center = [NSDistributedNotificationCenter defaultCenter]; if (![[NSFileManager defaultManager] fileExistsAtPath:wmDefaultsPath]) { /* TODO: WM doesn't track WM.plist changes if it doesn't exist. We need to send WMDidChangeWindowAppearanceSettings to the distributed notification center (WM should handle this notification and reread file). */ - center = [NSDistributedNotificationCenter defaultCenter]; NSLog(@"[Font] can't find existing WM defaults database! Creating new..."); wmDefaults = [NSMutableDictionary new]; } @@ -222,7 +221,7 @@ notification center (WM should handle this notification and reread file). */ [wmDefaults writeToFile:wmDefaultsPath atomically:YES]; [wmDefaults release]; if (center != nil) { - [center postNotificationName:@"WMDidChangeWindowAppearanceSettings" object:nil]; + [center postNotificationName:@"WMDidChangeWindowAppearanceSettings" object:@"GSWorkspaceNotification"]; } } From ef0ee64b7df1079fb20d788efc6acf57aef81297 Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Wed, 25 Oct 2023 14:36:45 +0300 Subject: [PATCH 45/67] return of WM preferences changs (WM.plist) tracking - font changes in Font Preferneces now accepted and applied by WM again. --- Applications/Preferences/Modules/Font/Font.m | 3 - .../Workspace/Preferences/Dock/DockPrefs.m | 2 +- Applications/Workspace/WM/WM.h | 4 +- Applications/Workspace/WM/appicon.c | 4 +- Applications/Workspace/WM/defaults.c | 645 +++++++++++------- Applications/Workspace/WM/defaults.h | 4 +- Applications/Workspace/WM/dock.c | 2 +- Applications/Workspace/WM/event.c | 4 +- Applications/Workspace/WM/screen.c | 3 +- Applications/Workspace/WM/startup.c | 27 +- Applications/Workspace/WM/window_attributes.c | 28 +- 11 files changed, 425 insertions(+), 301 deletions(-) diff --git a/Applications/Preferences/Modules/Font/Font.m b/Applications/Preferences/Modules/Font/Font.m index 73b335155..1aa15fbc8 100644 --- a/Applications/Preferences/Modules/Font/Font.m +++ b/Applications/Preferences/Modules/Font/Font.m @@ -220,9 +220,6 @@ notification center (WM should handle this notification and reread file). */ [wmDefaults setObject:value forKey:key]; [wmDefaults writeToFile:wmDefaultsPath atomically:YES]; [wmDefaults release]; - if (center != nil) { - [center postNotificationName:@"WMDidChangeWindowAppearanceSettings" object:@"GSWorkspaceNotification"]; - } } - (void)updateUI diff --git a/Applications/Workspace/Preferences/Dock/DockPrefs.m b/Applications/Workspace/Preferences/Dock/DockPrefs.m index 9d71b6621..c3f55c4bc 100644 --- a/Applications/Workspace/Preferences/Dock/DockPrefs.m +++ b/Applications/Workspace/Preferences/Dock/DockPrefs.m @@ -121,7 +121,7 @@ void WMSetDockAppImage(NSString *path, int position, BOOL save) CFMutableDictionaryRef winAttrs, appAttrs; CFStringRef appKey, iconFile; - winAttrs = w_global.domain.window_attr->dictionary; + winAttrs = w_global.domain.window_attrs->dictionary; appKey = CFStringCreateWithFormat(kCFAllocatorDefault, 0, CFSTR("%s.%s"), btn->wm_instance, btn->wm_class); diff --git a/Applications/Workspace/WM/WM.h b/Applications/Workspace/WM/WM.h index eb6d0bb34..71dddeff4 100644 --- a/Applications/Workspace/WM/WM.h +++ b/Applications/Workspace/WM/WM.h @@ -241,9 +241,9 @@ extern struct wm_global_variables { /* Global Domains, for storing dictionaries */ struct { /* Note: you must #include if you want to use them */ - struct WDDomain *wm; + struct WDDomain *wm_state; struct WDDomain *wm_preferences; - struct WDDomain *window_attr; + struct WDDomain *window_attrs; struct WDDomain *root_menu; } domain; diff --git a/Applications/Workspace/WM/appicon.c b/Applications/Workspace/WM/appicon.c index 23f25f3ae..8923dd3c8 100644 --- a/Applications/Workspace/WM/appicon.c +++ b/Applications/Workspace/WM/appicon.c @@ -955,7 +955,7 @@ Bool wHandleAppIconMove(WAppIcon *aicon, XEvent *event) static void wApplicationSaveIconPathFor(const char *iconPath, const char *wm_instance, const char *wm_class) { - CFMutableDictionaryRef dict = w_global.domain.window_attr->dictionary; + CFMutableDictionaryRef dict = w_global.domain.window_attrs->dictionary; CFMutableDictionaryRef adict = NULL; CFTypeRef val; CFStringRef key; @@ -994,7 +994,7 @@ static void wApplicationSaveIconPathFor(const char *iconPath, const char *wm_ins } if (val && !wPreferences.flags.noupdates) { - WMUserDefaultsWrite(w_global.domain.window_attr->dictionary, w_global.domain.window_attr->name); + WMUserDefaultsWrite(w_global.domain.window_attrs->dictionary, w_global.domain.window_attrs->name); } if (adict) { diff --git a/Applications/Workspace/WM/defaults.c b/Applications/Workspace/WM/defaults.c index 879a837b1..da95a1674 100644 --- a/Applications/Workspace/WM/defaults.c +++ b/Applications/Workspace/WM/defaults.c @@ -348,212 +348,324 @@ WDefaultEntry staticOptionList[] = { /* dynamic options */ WDefaultEntry optionList[] = { - {"IconPosition", "blh", seIconPositions, &wPreferences.icon_yard, getEnum, setIconPosition, NULL, NULL}, - {"IconificationStyle", "Zoom", seIconificationStyles, &wPreferences.iconification_style, getEnum, NULL, NULL, NULL}, - {"ImagePaths", DEF_IMAGE_PATHS, NULL, &wPreferences.image_paths, getPathList, NULL, NULL, NULL}, - {"ColormapMode", "Auto", seColormapModes, &wPreferences.colormap_mode, getEnum, NULL, NULL, NULL}, - {"AutoFocus", "YES", NULL, &wPreferences.auto_focus, getBool, NULL, NULL, NULL}, - {"RaiseDelay", "0", NULL, &wPreferences.raise_delay, getInt, NULL, NULL, NULL}, - {"CirculateRaise", "YES", NULL, &wPreferences.circ_raise, getBool, NULL, NULL, NULL}, - {"Superfluous", "YES", NULL, &wPreferences.superfluous, getBool, NULL, NULL, NULL}, - {"StickyIcons", "YES", NULL, &wPreferences.sticky_icons, getBool, setStickyIcons, NULL, NULL}, - {"SaveSessionOnExit", "NO", NULL, &wPreferences.save_session_on_exit, getBool, NULL, NULL, NULL}, - {"ScrollableMenus", "YES", NULL, &wPreferences.scrollable_menus, getBool, NULL, NULL, NULL}, - {"MenuScrollSpeed", "medium", seSpeeds, &wPreferences.menu_scroll_speed, getEnum, NULL, NULL, NULL}, - {"IconSlideSpeed", "Slow", seSpeeds, &wPreferences.icon_slide_speed, getEnum, NULL, NULL, NULL}, - {"ClipAutoraiseDelay", "600", NULL, &wPreferences.clip_auto_raise_delay, getInt, NULL, NULL, NULL}, - {"ClipAutolowerDelay", "1000", NULL, &wPreferences.clip_auto_lower_delay, getInt, NULL, NULL, NULL}, - {"ClipAutoexpandDelay", "600", NULL, &wPreferences.clip_auto_expand_delay, getInt, NULL, NULL, NULL}, - {"ClipAutocollapseDelay", "1000", NULL, &wPreferences.clip_auto_collapse_delay, getInt, NULL, NULL, NULL}, - {"WrapAppiconsInDock", "NO", NULL, NULL, getBool, setWrapAppiconsInDock, NULL, NULL}, - {"AlignSubmenus", "YES", NULL, &wPreferences.align_menus, getBool, NULL, NULL, NULL}, - {"ViKeyMenus", "NO", NULL, &wPreferences.vi_key_menus, getBool, NULL, NULL, NULL}, - {"OpenTransientOnOwnerWorkspace", "YES", NULL, &wPreferences.open_transients_with_parent, getBool, NULL, NULL, NULL}, - {"WindowPlacement", "cascade", sePlacements, &wPreferences.window_placement, getEnum, NULL, NULL, NULL}, - {"IgnoreFocusClick", "NO", NULL, &wPreferences.ignore_focus_click, getBool, NULL, NULL, NULL}, - {"UseSaveUnders", "NO", NULL, &wPreferences.use_saveunders, getBool, NULL, NULL, NULL}, - {"OpaqueMove", "YES", NULL, &wPreferences.opaque_move, getBool, NULL, NULL, NULL}, - {"OpaqueResize", "NO", NULL, &wPreferences.opaque_resize, getBool, NULL, NULL, NULL}, - {"OpaqueMoveResizeKeyboard", "NO", NULL, &wPreferences.opaque_move_resize_keyboard, getBool, NULL, NULL, NULL}, - {"DisableAnimations", "NO", NULL, &wPreferences.no_animations, getBool, NULL, NULL, NULL}, - {"DontLinkWorkspaces", "NO", NULL, &wPreferences.no_autowrap, getBool, NULL, NULL, NULL}, - {"WindowSnapping", "NO", NULL, &wPreferences.window_snapping, getBool, NULL, NULL, NULL}, - {"SnapEdgeDetect", "1", NULL, &wPreferences.snap_edge_detect, getInt, NULL, NULL, NULL}, - {"SnapCornerDetect", "10", NULL, &wPreferences.snap_corner_detect, getInt, NULL, NULL, NULL}, - {"DragMaximizedWindow", "Move", seDragMaximizedWindow, &wPreferences.drag_maximized_window, getEnum, NULL, NULL, NULL}, - {"AutoArrangeIcons", "NO", NULL, &wPreferences.auto_arrange_icons, getBool, NULL, NULL, NULL}, - {"NoWindowOverDock", "YES", NULL, &wPreferences.no_window_over_dock, getBool, updateUsableArea, NULL, NULL}, - {"NoWindowOverIcons", "YES", NULL, &wPreferences.no_window_over_icons, getBool, updateUsableArea, NULL, NULL}, - {"WindowPlaceOrigin", "(100, 100)", NULL, &wPreferences.window_place_origin, getCoord, NULL, NULL, NULL}, - {"ResizeDisplay", "Titlebar", seGeomDisplays, &wPreferences.size_display, getEnum, NULL, NULL, NULL}, - {"MoveDisplay", "Titlebar", seGeomDisplays, &wPreferences.move_display, getEnum, NULL, NULL, NULL}, - {"DontConfirmKill", "NO", NULL, &wPreferences.dont_confirm_kill, getBool, NULL, NULL, NULL}, - {"WindowTitleBalloons", "NO", NULL, &wPreferences.window_balloon, getBool, NULL, NULL, NULL}, - {"MiniwindowTitleBalloons", "YES", NULL, &wPreferences.miniwin_title_balloon, getBool, NULL, NULL, NULL}, - {"MiniwindowPreviewBalloons", "NO", NULL, &wPreferences.miniwin_preview_balloon, getBool, NULL, NULL, NULL}, - {"AppIconBalloons", "NO", NULL, &wPreferences.appicon_balloon, getBool, NULL, NULL, NULL}, - {"HelpBalloons", "NO", NULL, &wPreferences.help_balloon, getBool, NULL, NULL, NULL}, - {"EdgeResistance", "30", NULL, &wPreferences.edge_resistance, getInt, NULL, NULL, NULL}, - {"ResizeIncrement", "0", NULL, &wPreferences.resize_increment, getInt, NULL, NULL, NULL}, - {"Attraction", "NO", NULL, &wPreferences.attract, getBool, NULL, NULL, NULL}, - {"DisableBlinking", "NO", NULL, &wPreferences.dont_blink, getBool, NULL, NULL, NULL}, - {"SingleClickLaunch", "NO", NULL, &wPreferences.single_click, getBool, NULL, NULL, NULL}, - {"StrictWindozeCycle", "YES", NULL, &wPreferences.strict_windoze_cycle, getBool, NULL, NULL, - NULL}, - {"SwitchPanelOnlyOpen", "NO", NULL, &wPreferences.panel_only_open, getBool, NULL, NULL, NULL}, - {"MiniPreviewSize", "128", NULL, &wPreferences.minipreview_size, getInt, NULL, NULL, NULL}, - {"IgnoreGtkHints", "NO", NULL, &wPreferences.ignore_gtk_decoration_hints, getBool, NULL, NULL, - NULL}, - - /* --- Mouse options --- */ - - {"DoubleClickTime", "350", (void *)&wPreferences.dblclick_time, &wPreferences.dblclick_time, getInt, setDoubleClick, NULL, NULL}, - {"DisableWSMouseActions", "NO", NULL, &wPreferences.disable_root_mouse, getBool, NULL, NULL, NULL}, - {"MouseLeftButtonAction", "SelectWindows", seMouseButtonActions, &wPreferences.mouse_button1, getEnum, NULL, NULL, NULL}, - {"MouseMiddleButtonAction", "OpenWindowListMenu", seMouseButtonActions, &wPreferences.mouse_button2, getEnum, NULL, NULL, NULL}, - {"MouseRightButtonAction", "OpenApplicationsMenu", seMouseButtonActions, &wPreferences.mouse_button3, getEnum, NULL, NULL, NULL}, - {"MouseBackwardButtonAction", "None", seMouseButtonActions, &wPreferences.mouse_button8, getEnum, NULL, NULL, NULL}, - {"MouseForwardButtonAction", "None", seMouseButtonActions, &wPreferences.mouse_button9, getEnum, NULL, NULL, NULL}, - {"MouseWheelAction", "None", seMouseWheelActions, &wPreferences.mouse_wheel_scroll, getEnum, NULL, NULL, NULL}, - {"MouseWheelTiltAction", "None", seMouseWheelActions, &wPreferences.mouse_wheel_tilt, getEnum, NULL, NULL, NULL}, - - /* --- Workspaces --- */ - - {"AdvanceToNewWorkspace", "NO", NULL, &wPreferences.ws_advance, getBool, NULL, NULL, NULL}, - {"CycleWorkspaces", "NO", NULL, &wPreferences.ws_cycle, getBool, NULL, NULL, NULL}, - {"WorkspaceNameDisplayPosition", "center", seDisplayPositions, &wPreferences.workspace_name_display_position, getEnum, NULL, NULL, NULL}, - {"WorkspaceBorder", "AllDirections", seWorkspaceBorder, &wPreferences.workspace_border_position, getEnum, updateUsableArea, NULL, NULL}, - {"WorkspaceBorderSize", "0", NULL, &wPreferences.workspace_border_size, getInt, updateUsableArea, NULL, NULL}, - - /* --- Animations --- */ - - {"ShadeSpeed", "medium", seSpeeds, &wPreferences.shade_speed, getEnum, NULL, NULL, NULL}, - {"BounceAppIconsWhenUrgent", "YES", NULL, &wPreferences.bounce_appicons_when_urgent, getBool, NULL, NULL, NULL}, - {"RaiseAppIconsWhenBouncing", "NO", NULL, &wPreferences.raise_appicons_when_bouncing, getBool, NULL, NULL, NULL}, - {"DoNotMakeAppIconsBounce", "YES", NULL, &wPreferences.do_not_make_appicons_bounce, getBool, NULL, NULL, NULL}, - - /* --- Options need to get rid of or fix --- */ - - /* --- Style options --- */ - - {"MenuStyle", "normal", seMenuStyles, &wPreferences.menu_style, getEnum, setMenuStyle, NULL, NULL}, - {"WidgetColor", "(solid, \"#aaaaaa\")", NULL, NULL, getTexture, setWidgetColor, NULL, NULL}, - {"IconBack", "(\"tpixmap\", \"/Library/Images/common_Tile.tiff\", \"#000000\")", NULL, NULL, getTexture, setIconTile, NULL, NULL}, - {"MiniwindowBack", "(\"tpixmap\", \"/Library/Images/common_MiniWindowTile.tiff\", \"#000000\")", NULL, NULL, getTexture, setMiniwindowTile, NULL, NULL}, /* NEXTSPACE */ - {"TitleJustify", "center", seJustifications, &wPreferences.title_justification, getEnum, setJustify, NULL, NULL}, - {"WindowTitleFont", DEF_TITLE_FONT, NULL, NULL, getFont, setWinTitleFont, NULL, NULL}, {"WindowTitleExtendSpace", DEF_WINDOW_TITLE_EXTEND_SPACE, NULL, &wPreferences.window_title_clearance, getInt, setClearance, NULL, NULL}, - {"WindowTitleMinHeight", "22", NULL, &wPreferences.window_title_min_height, getInt, setClearance, NULL, NULL}, - {"WindowTitleMaxHeight", "22", NULL, &wPreferences.window_title_max_height, getInt, setClearance, NULL, NULL}, - {"MenuTitleExtendSpace", DEF_MENU_TITLE_EXTEND_SPACE, NULL, &wPreferences.menu_title_clearance, getInt, setClearance, NULL, NULL}, - {"MenuTitleMinHeight", "22", NULL, &wPreferences.menu_title_min_height, getInt, setClearance, NULL, NULL}, - {"MenuTitleMaxHeight", "22", NULL, &wPreferences.menu_title_max_height, getInt, setClearance, NULL, NULL}, - {"MenuTextExtendSpace", DEF_MENU_TEXT_EXTEND_SPACE, NULL, &wPreferences.menu_text_clearance, getInt, setClearance, NULL, NULL}, - {"MenuTitleFont", DEF_MENU_TITLE_FONT, NULL, NULL, getFont, setMenuTitleFont, NULL, NULL}, - {"MenuTextFont", DEF_MENU_ENTRY_FONT, NULL, NULL, getFont, setMenuTextFont, NULL, NULL}, - {"IconTitleFont", DEF_ICON_TITLE_FONT, NULL, NULL, getFont, setIconTitleFont, NULL, NULL}, - {"ClipTitleFont", DEF_CLIP_TITLE_FONT, NULL, NULL, getFont, setClipTitleFont, NULL, NULL}, - {"ShowClipTitle", "YES", NULL, &wPreferences.show_clip_title, getBool, NULL, NULL, NULL}, - {"LargeDisplayFont", DEF_WORKSPACE_NAME_FONT, NULL, NULL, getFont, setLargeDisplayFont, NULL, NULL}, - {"HighlightColor", "white", NULL, NULL, getColor, setHightlight, NULL, NULL}, - {"HighlightTextColor", "black", NULL, NULL, getColor, setHightlightText, NULL, NULL}, - {"ClipTitleColor", "black", (void *)CLIP_NORMAL, NULL, getColor, setClipTitleColor, NULL, NULL}, - {"CClipTitleColor", "\"#454045\"", (void *)CLIP_COLLAPSED, NULL, getColor, setClipTitleColor, NULL, NULL}, - {"FTitleColor", "white", (void *)WS_FOCUSED, NULL, getColor, setWTitleColor, NULL, NULL}, - {"PTitleColor", "white", (void *)WS_PFOCUSED, NULL, getColor, setWTitleColor, NULL, NULL}, - {"UTitleColor", "black", (void *)WS_UNFOCUSED, NULL, getColor, setWTitleColor, NULL, NULL}, - {"FTitleBack", "(solid, black)", NULL, NULL, getTexture, setFTitleBack, NULL, NULL}, - {"PTitleBack", "(solid, \"#555555\")", NULL, NULL, getTexture, setPTitleBack, NULL, NULL}, - {"UTitleBack", "(solid, \"#aaaaaa\")", NULL, NULL, getTexture, setUTitleBack, NULL, NULL}, - {"ResizebarBack", "(solid, \"#aaaaaa\")", NULL, NULL, getTexture, setResizebarBack, NULL, NULL}, - {"MenuTitleColor", "white", NULL, NULL, getColor, setMenuTitleColor, NULL, NULL}, - {"MenuTextColor", "black", NULL, NULL, getColor, setMenuTextColor, NULL, NULL}, - {"MenuDisabledColor", "\"#555555\"", NULL, NULL, getColor, setMenuDisabledColor, NULL, NULL}, - {"MenuTitleBack", "(solid, black)", NULL, NULL, getTexture, setMenuTitleBack, NULL, NULL}, - {"MenuTextBack", "(solid, \"#aaaaaa\")", NULL, NULL, getTexture, setMenuTextBack, NULL, NULL}, - {"IconTitleColor", "white", NULL, NULL, getColor, setIconTitleColor, NULL, NULL}, - {"IconTitleBack", "black", NULL, NULL, getColor, setIconTitleBack, NULL, NULL}, - {"SwitchPanelImages", "(swtile.png, swback.png, 30, 40)", &wPreferences, NULL, getPropList, setSwPOptions, NULL, NULL}, - {"ModifierKeyLabels", "(\"Shift+\", \"Control+\", \"Alt+\", \"Mod2+\", \"Mod3+\", \"Super+\", \"Mod5+\")", &wPreferences, NULL, getPropList, setModifierKeyLabels, NULL, NULL}, - {"FrameBorderWidth", "1", NULL, NULL, getInt, setFrameBorderWidth, NULL, NULL}, - {"FrameBorderColor", "black", NULL, NULL, getColor, setFrameBorderColor, NULL, NULL}, - {"FrameFocusedBorderColor", "black", NULL, NULL, getColor, setFrameFocusedBorderColor, NULL, NULL}, - {"FrameSelectedBorderColor", "white", NULL, NULL, getColor, setFrameSelectedBorderColor, NULL, NULL}, - {"WorkspaceMapBack", "(solid, black)", NULL, NULL, getTexture, setWorkspaceMapBackground, NULL, NULL}, - - /* --- Key bindings --- */ - - {"CommandModifierKey", "Alt", NULL, &wPreferences.cmd_modifier_mask, getModMask, NULL, NULL, NULL}, - {"AlternateModifierKey", "Super", NULL, &wPreferences.alt_modifier_mask, getAltModMask, NULL, NULL, NULL}, - /* Dock and Icon Yard */ - /* {"DockHideShowKey", "\"Alternate+D\"", (void *)WKBD_DOCKHIDESHOW, NULL, getKeybind, setKeyGrab, NULL, NULL}, */ - /* {"IconYardHideShowKey", "\"Alternate+Y\"", (void *)WKBD_YARDHIDESHOW, NULL, getKeybind, setKeyGrab, NULL, NULL}, */ - /* Window Resizing */ - /* {"MaximusKey", "\"Super+KP_5\"", (void *)WKBD_MAXIMUS, NULL, getKeybind, setKeyGrab, NULL, NULL}, */ - /* {"ShadeKey", "\"Alternate+KP_Subtract\"", (void *)WKBD_SHADE, NULL, getKeybind, setKeyGrab, NULL, NULL}, */ - /* {"MaximizeKey", "\"Alternate+KP_Add\"", (void *)WKBD_MAXIMIZE, NULL, getKeybind, setKeyGrab, NULL, NULL}, */ - /* {"VMaximizeKey", "\"Alternate+Up\"", (void *)WKBD_VMAXIMIZE, NULL, getKeybind, setKeyGrab, NULL, NULL}, */ - /* {"HMaximizeKey", "\"Alternate+Right\"", (void *)WKBD_HMAXIMIZE, NULL, getKeybind, setKeyGrab, NULL, NULL}, */ - /* {"LHMaximizeKey", "\"Alternate+KP_4\"", (void *)WKBD_LHMAXIMIZE, NULL, getKeybind, setKeyGrab, NULL, NULL}, */ - /* {"RHMaximizeKey", "\"Alternate+KP_6\"", (void *)WKBD_RHMAXIMIZE, NULL, getKeybind, setKeyGrab, NULL, NULL}, */ - /* {"THMaximizeKey", "\"Alternate+KP_8\"", (void *)WKBD_THMAXIMIZE, NULL, getKeybind, setKeyGrab, NULL, NULL}, */ - /* {"BHMaximizeKey", "\"Alternate+KP_2\"", (void *)WKBD_BHMAXIMIZE, NULL, getKeybind, setKeyGrab, NULL, NULL}, */ - /* {"LTCMaximizeKey", "\"Alternate+KP_7\"", (void *)WKBD_LTCMAXIMIZE, NULL, getKeybind, setKeyGrab, NULL, NULL}, */ - /* {"RTCMaximizeKey", "\"Alternate+KP_9\"", (void *)WKBD_RTCMAXIMIZE, NULL, getKeybind, setKeyGrab, NULL, NULL}, */ - /* {"LBCMaximizeKey", "\"Alternate+KP_1\"", (void *)WKBD_LBCMAXIMIZE, NULL, getKeybind, setKeyGrab, NULL, NULL}, */ - /* {"RBCMaximizeKey", "\"Alternate+KP_3\"", (void *)WKBD_RBCMAXIMIZE, NULL, getKeybind, setKeyGrab, NULL, NULL}, */ - /* Window Ordering */ - /* {"CloseKey", "\"Command+w\"", (void *)WKBD_CLOSE, NULL, getKeybind, setKeyGrab, NULL, NULL}, */ - /* {"HideKey", "\"Command+h\"", (void *)WKBD_HIDE, NULL, getKeybind, setKeyGrab, NULL, NULL}, */ - /* {"HideOthersKey", "\"Command+H\"", (void *)WKBD_HIDE_OTHERS, NULL, getKeybind, setKeyGrab, NULL, NULL}, */ - /* {"MiniaturizeKey", "\"Command+m\"", (void *)WKBD_MINIATURIZE, NULL, getKeybind, setKeyGrab, NULL, NULL}, */ - /* {"MinimizeAllKey", "\"Command+M\"", (void *)WKBD_MINIMIZEALL, NULL, getKeybind, setKeyGrab, NULL, NULL}, */ - /* Focus switch */ - /* {"RaiseKey", "\"Command+Up\"", (void *)WKBD_RAISE, NULL, getKeybind, setKeyGrab, NULL, NULL}, */ - /* {"LowerKey", "\"Command+Down\"", (void *)WKBD_LOWER, NULL, getKeybind, setKeyGrab, NULL, NULL}, */ - {"FocusNextKey", "\"Command+Tab\"", (void *)WKBD_FOCUSNEXT, NULL, getKeybind, setKeyGrab, NULL, NULL}, - {"FocusPrevKey", "\"Command+Shift+Tab\"", (void *)WKBD_FOCUSPREV, NULL, getKeybind, setKeyGrab, NULL, NULL}, - {"GroupNextKey", "\"Command+grave\"", (void *)WKBD_GROUPNEXT, NULL, getKeybind, setKeyGrab, NULL, NULL}, - {"GroupPrevKey", "\"Command+Shift+grave\"", (void *)WKBD_GROUPPREV, NULL, getKeybind, setKeyGrab, NULL, NULL}, - /* Workspaces */ - {"NextWorkspaceKey", "\"Control+Right\"", (void *)WKBD_NEXT_DESKTOP, NULL, getKeybind, setKeyGrab, NULL, NULL}, - {"PrevWorkspaceKey", "\"Control+Left\"", (void *)WKBD_PREV_DESKTOP, NULL, getKeybind, setKeyGrab, NULL, NULL}, - {"LastWorkspaceKey", "None", (void *)WKBD_LAST_DESKTOP, NULL, getKeybind, setKeyGrab, NULL, NULL}, - {"Desktop1Key", "\"Control+1\"", (void *)WKBD_DESKTOP_1, NULL, getKeybind, setKeyGrab, NULL, NULL}, - {"Desktop2Key", "\"Control+2\"", (void *)WKBD_DESKTOP_2, NULL, getKeybind, setKeyGrab, NULL, NULL}, - {"Desktop3Key", "\"Control+3\"", (void *)WKBD_DESKTOP_3, NULL, getKeybind, setKeyGrab, NULL, NULL}, - {"Desktop4Key", "\"Control+4\"", (void *)WKBD_DESKTOP_4, NULL, getKeybind, setKeyGrab, NULL, NULL}, - {"Desktop5Key", "\"Control+5\"", (void *)WKBD_DESKTOP_5, NULL, getKeybind, setKeyGrab, NULL, NULL}, - {"Desktop6Key", "\"Control+6\"", (void *)WKBD_DESKTOP_6, NULL, getKeybind, setKeyGrab, NULL, NULL}, - {"Desktop7Key", "\"Control+7\"", (void *)WKBD_DESKTOP_7, NULL, getKeybind, setKeyGrab, NULL, NULL}, - {"Desktop8Key", "\"Control+8\"", (void *)WKBD_DESKTOP_8, NULL, getKeybind, setKeyGrab, NULL, NULL}, - {"Desktop9Key", "\"Control+9\"", (void *)WKBD_DESKTOP_9, NULL, getKeybind, setKeyGrab, NULL, NULL}, - {"Desktop10Key", "\"Control+0\"", (void *)WKBD_DESKTOP_10, NULL, getKeybind, setKeyGrab, NULL, NULL}, - - {"WindowRelaunchKey", "None", (void *)WKBD_RELAUNCH, NULL, getKeybind, setKeyGrab, NULL, NULL}, - - /* --- Mouse cursors --- */ - {"NormalCursor", "(builtin, left_ptr)", (void *)WCUR_ROOT, NULL, getCursor, setCursor, NULL, NULL}, - {"ArrowCursor", "(builtin, left_ptr)", (void *)WCUR_ARROW, NULL, getCursor, setCursor, NULL, NULL}, - {"ResizeCursor", "(builtin, sizing)", (void *)WCUR_RESIZE, NULL, getCursor, setCursor, NULL, NULL}, - {"WaitCursor", "(builtin, watch)", (void *)WCUR_WAIT, NULL, getCursor, setCursor, NULL, NULL}, - {"QuestionCursor", "(builtin, question_arrow)", (void *)WCUR_QUESTION, NULL, getCursor, setCursor, NULL, NULL}, - {"TextCursor", "(builtin, xterm)", (void *)WCUR_TEXT, NULL, getCursor, setCursor, NULL, NULL}, - {"SelectCursor", "(builtin, cross)", (void *)WCUR_SELECT, NULL, getCursor, setCursor, NULL, NULL}, - {"MoveCursor", "(library, move)", (void *)WCUR_MOVE, NULL, getCursor, setCursor, NULL, NULL}, - {"TopLeftResizeCursor", "(library, bd_double_arrow)", (void *)WCUR_TOPLEFTRESIZE, NULL, getCursor, setCursor, NULL, NULL}, - {"TopRightResizeCursor", "(library, fd_double_arrow)", (void *)WCUR_TOPRIGHTRESIZE, NULL, getCursor, setCursor, NULL, NULL}, - {"BottomLeftResizeCursor", "(library, fd_double_arrow)", (void *)WCUR_BOTTOMLEFTRESIZE, NULL, getCursor, setCursor, NULL, NULL}, - {"BottomRightResizeCursor", "(library, bd_double_arrow)", (void *)WCUR_BOTTOMRIGHTRESIZE, NULL, getCursor, setCursor, NULL, NULL}, - {"VerticalResizeCursor", "(library, wm_v_double_arrow)", (void *)WCUR_VERTICALRESIZE, NULL, getCursor, setCursor, NULL, NULL}, - {"HorizontalResizeCursor", "(library, wm_h_double_arrow)", (void *)WCUR_HORIZONRESIZE, NULL, getCursor, setCursor, NULL, NULL}, - {"UpResizeCursor", "(library, wm_up_arrow)", (void *)WCUR_UPRESIZE, NULL, getCursor, setCursor, NULL, NULL}, - {"DownResizeCursor", "(library, wm_down_arrow)", (void *)WCUR_DOWNRESIZE, NULL, getCursor, setCursor, NULL, NULL}, - {"LeftResizeCursor", "(library, wm_left_arrow)", (void *)WCUR_LEFTRESIZE, NULL, getCursor, setCursor, NULL, NULL}, - {"RightResizeCursor", "(library, wm_right_arrow)", (void *)WCUR_RIGHTRESIZE, NULL, getCursor, setCursor, NULL, NULL}, - {"DialogHistoryLines", "500", NULL, &wPreferences.history_lines, getInt, NULL, NULL, NULL}, - {"CycleActiveHeadOnly", "NO", NULL, &wPreferences.cycle_active_head_only, getBool, NULL, NULL, NULL}, - {"CycleIgnoreMinimized", "NO", NULL, &wPreferences.cycle_ignore_minimized, getBool, NULL, NULL, NULL} -}; + {"IconPosition", "blh", seIconPositions, &wPreferences.icon_yard, getEnum, setIconPosition, + NULL, NULL}, + {"IconificationStyle", "Zoom", seIconificationStyles, &wPreferences.iconification_style, + getEnum, NULL, NULL, NULL}, + {"ImagePaths", DEF_IMAGE_PATHS, NULL, &wPreferences.image_paths, getPathList, NULL, NULL, NULL}, + {"ColormapMode", "Auto", seColormapModes, &wPreferences.colormap_mode, getEnum, NULL, NULL, + NULL}, + {"AutoFocus", "YES", NULL, &wPreferences.auto_focus, getBool, NULL, NULL, NULL}, + {"RaiseDelay", "0", NULL, &wPreferences.raise_delay, getInt, NULL, NULL, NULL}, + {"CirculateRaise", "YES", NULL, &wPreferences.circ_raise, getBool, NULL, NULL, NULL}, + {"Superfluous", "YES", NULL, &wPreferences.superfluous, getBool, NULL, NULL, NULL}, + {"StickyIcons", "YES", NULL, &wPreferences.sticky_icons, getBool, setStickyIcons, NULL, NULL}, + {"SaveSessionOnExit", "NO", NULL, &wPreferences.save_session_on_exit, getBool, NULL, NULL, + NULL}, + {"ScrollableMenus", "YES", NULL, &wPreferences.scrollable_menus, getBool, NULL, NULL, NULL}, + {"MenuScrollSpeed", "medium", seSpeeds, &wPreferences.menu_scroll_speed, getEnum, NULL, NULL, + NULL}, + {"IconSlideSpeed", "Slow", seSpeeds, &wPreferences.icon_slide_speed, getEnum, NULL, NULL, NULL}, + {"ClipAutoraiseDelay", "600", NULL, &wPreferences.clip_auto_raise_delay, getInt, NULL, NULL, + NULL}, + {"ClipAutolowerDelay", "1000", NULL, &wPreferences.clip_auto_lower_delay, getInt, NULL, NULL, + NULL}, + {"ClipAutoexpandDelay", "600", NULL, &wPreferences.clip_auto_expand_delay, getInt, NULL, NULL, + NULL}, + {"ClipAutocollapseDelay", "1000", NULL, &wPreferences.clip_auto_collapse_delay, getInt, NULL, + NULL, NULL}, + {"WrapAppiconsInDock", "NO", NULL, NULL, getBool, setWrapAppiconsInDock, NULL, NULL}, + {"AlignSubmenus", "YES", NULL, &wPreferences.align_menus, getBool, NULL, NULL, NULL}, + {"ViKeyMenus", "NO", NULL, &wPreferences.vi_key_menus, getBool, NULL, NULL, NULL}, + {"OpenTransientOnOwnerWorkspace", "YES", NULL, &wPreferences.open_transients_with_parent, + getBool, NULL, NULL, NULL}, + {"WindowPlacement", "cascade", sePlacements, &wPreferences.window_placement, getEnum, NULL, + NULL, NULL}, + {"IgnoreFocusClick", "NO", NULL, &wPreferences.ignore_focus_click, getBool, NULL, NULL, NULL}, + {"UseSaveUnders", "NO", NULL, &wPreferences.use_saveunders, getBool, NULL, NULL, NULL}, + {"OpaqueMove", "YES", NULL, &wPreferences.opaque_move, getBool, NULL, NULL, NULL}, + {"OpaqueResize", "NO", NULL, &wPreferences.opaque_resize, getBool, NULL, NULL, NULL}, + {"OpaqueMoveResizeKeyboard", "NO", NULL, &wPreferences.opaque_move_resize_keyboard, getBool, + NULL, NULL, NULL}, + {"DisableAnimations", "NO", NULL, &wPreferences.no_animations, getBool, NULL, NULL, NULL}, + {"DontLinkWorkspaces", "NO", NULL, &wPreferences.no_autowrap, getBool, NULL, NULL, NULL}, + {"WindowSnapping", "NO", NULL, &wPreferences.window_snapping, getBool, NULL, NULL, NULL}, + {"SnapEdgeDetect", "1", NULL, &wPreferences.snap_edge_detect, getInt, NULL, NULL, NULL}, + {"SnapCornerDetect", "10", NULL, &wPreferences.snap_corner_detect, getInt, NULL, NULL, NULL}, + {"DragMaximizedWindow", "Move", seDragMaximizedWindow, &wPreferences.drag_maximized_window, + getEnum, NULL, NULL, NULL}, + {"AutoArrangeIcons", "NO", NULL, &wPreferences.auto_arrange_icons, getBool, NULL, NULL, NULL}, + {"NoWindowOverDock", "YES", NULL, &wPreferences.no_window_over_dock, getBool, updateUsableArea, + NULL, NULL}, + {"NoWindowOverIcons", "YES", NULL, &wPreferences.no_window_over_icons, getBool, + updateUsableArea, NULL, NULL}, + {"WindowPlaceOrigin", "(100, 100)", NULL, &wPreferences.window_place_origin, getCoord, NULL, + NULL, NULL}, + {"ResizeDisplay", "Titlebar", seGeomDisplays, &wPreferences.size_display, getEnum, NULL, NULL, + NULL}, + {"MoveDisplay", "Titlebar", seGeomDisplays, &wPreferences.move_display, getEnum, NULL, NULL, + NULL}, + {"DontConfirmKill", "NO", NULL, &wPreferences.dont_confirm_kill, getBool, NULL, NULL, NULL}, + {"WindowTitleBalloons", "NO", NULL, &wPreferences.window_balloon, getBool, NULL, NULL, NULL}, + {"MiniwindowTitleBalloons", "YES", NULL, &wPreferences.miniwin_title_balloon, getBool, NULL, + NULL, NULL}, + {"MiniwindowPreviewBalloons", "NO", NULL, &wPreferences.miniwin_preview_balloon, getBool, NULL, + NULL, NULL}, + {"AppIconBalloons", "NO", NULL, &wPreferences.appicon_balloon, getBool, NULL, NULL, NULL}, + {"HelpBalloons", "NO", NULL, &wPreferences.help_balloon, getBool, NULL, NULL, NULL}, + {"EdgeResistance", "30", NULL, &wPreferences.edge_resistance, getInt, NULL, NULL, NULL}, + {"ResizeIncrement", "0", NULL, &wPreferences.resize_increment, getInt, NULL, NULL, NULL}, + {"Attraction", "NO", NULL, &wPreferences.attract, getBool, NULL, NULL, NULL}, + {"DisableBlinking", "NO", NULL, &wPreferences.dont_blink, getBool, NULL, NULL, NULL}, + {"SingleClickLaunch", "NO", NULL, &wPreferences.single_click, getBool, NULL, NULL, NULL}, + {"StrictWindozeCycle", "YES", NULL, &wPreferences.strict_windoze_cycle, getBool, NULL, NULL, + NULL}, + {"SwitchPanelOnlyOpen", "NO", NULL, &wPreferences.panel_only_open, getBool, NULL, NULL, NULL}, + {"MiniPreviewSize", "128", NULL, &wPreferences.minipreview_size, getInt, NULL, NULL, NULL}, + {"IgnoreGtkHints", "NO", NULL, &wPreferences.ignore_gtk_decoration_hints, getBool, NULL, NULL, + NULL}, + + /* --- Mouse options --- */ + + {"DoubleClickTime", "350", (void *)&wPreferences.dblclick_time, &wPreferences.dblclick_time, + getInt, setDoubleClick, NULL, NULL}, + {"DisableWSMouseActions", "NO", NULL, &wPreferences.disable_root_mouse, getBool, NULL, NULL, + NULL}, + {"MouseLeftButtonAction", "SelectWindows", seMouseButtonActions, &wPreferences.mouse_button1, + getEnum, NULL, NULL, NULL}, + {"MouseMiddleButtonAction", "OpenWindowListMenu", seMouseButtonActions, + &wPreferences.mouse_button2, getEnum, NULL, NULL, NULL}, + {"MouseRightButtonAction", "OpenApplicationsMenu", seMouseButtonActions, + &wPreferences.mouse_button3, getEnum, NULL, NULL, NULL}, + {"MouseBackwardButtonAction", "None", seMouseButtonActions, &wPreferences.mouse_button8, + getEnum, NULL, NULL, NULL}, + {"MouseForwardButtonAction", "None", seMouseButtonActions, &wPreferences.mouse_button9, getEnum, + NULL, NULL, NULL}, + {"MouseWheelAction", "None", seMouseWheelActions, &wPreferences.mouse_wheel_scroll, getEnum, + NULL, NULL, NULL}, + {"MouseWheelTiltAction", "None", seMouseWheelActions, &wPreferences.mouse_wheel_tilt, getEnum, + NULL, NULL, NULL}, + + /* --- Workspaces --- */ + + {"AdvanceToNewWorkspace", "NO", NULL, &wPreferences.ws_advance, getBool, NULL, NULL, NULL}, + {"CycleWorkspaces", "NO", NULL, &wPreferences.ws_cycle, getBool, NULL, NULL, NULL}, + {"WorkspaceNameDisplayPosition", "center", seDisplayPositions, + &wPreferences.workspace_name_display_position, getEnum, NULL, NULL, NULL}, + {"WorkspaceBorder", "AllDirections", seWorkspaceBorder, &wPreferences.workspace_border_position, + getEnum, updateUsableArea, NULL, NULL}, + {"WorkspaceBorderSize", "0", NULL, &wPreferences.workspace_border_size, getInt, + updateUsableArea, NULL, NULL}, + + /* --- Animations --- */ + + {"ShadeSpeed", "medium", seSpeeds, &wPreferences.shade_speed, getEnum, NULL, NULL, NULL}, + {"BounceAppIconsWhenUrgent", "YES", NULL, &wPreferences.bounce_appicons_when_urgent, getBool, + NULL, NULL, NULL}, + {"RaiseAppIconsWhenBouncing", "NO", NULL, &wPreferences.raise_appicons_when_bouncing, getBool, + NULL, NULL, NULL}, + {"DoNotMakeAppIconsBounce", "YES", NULL, &wPreferences.do_not_make_appicons_bounce, getBool, + NULL, NULL, NULL}, + + /* --- Options need to get rid of or fix --- */ + + /* --- Style options --- */ + + {"MenuStyle", "normal", seMenuStyles, &wPreferences.menu_style, getEnum, setMenuStyle, NULL, + NULL}, + {"WidgetColor", "(solid, \"#aaaaaa\")", NULL, NULL, getTexture, setWidgetColor, NULL, NULL}, + {"IconBack", "(\"tpixmap\", \"/Library/Images/common_Tile.tiff\", \"#000000\")", NULL, NULL, + getTexture, setIconTile, NULL, NULL}, + {"MiniwindowBack", "(\"tpixmap\", \"/Library/Images/common_MiniWindowTile.tiff\", \"#000000\")", + NULL, NULL, getTexture, setMiniwindowTile, NULL, NULL}, /* NEXTSPACE */ + {"TitleJustify", "center", seJustifications, &wPreferences.title_justification, getEnum, + setJustify, NULL, NULL}, + {"WindowTitleFont", DEF_TITLE_FONT, NULL, NULL, getFont, setWinTitleFont, NULL, NULL}, + {"WindowTitleExtendSpace", DEF_WINDOW_TITLE_EXTEND_SPACE, NULL, + &wPreferences.window_title_clearance, getInt, setClearance, NULL, NULL}, + {"WindowTitleMinHeight", "22", NULL, &wPreferences.window_title_min_height, getInt, + setClearance, NULL, NULL}, + {"WindowTitleMaxHeight", "22", NULL, &wPreferences.window_title_max_height, getInt, + setClearance, NULL, NULL}, + {"MenuTitleExtendSpace", DEF_MENU_TITLE_EXTEND_SPACE, NULL, &wPreferences.menu_title_clearance, + getInt, setClearance, NULL, NULL}, + {"MenuTitleMinHeight", "22", NULL, &wPreferences.menu_title_min_height, getInt, setClearance, + NULL, NULL}, + {"MenuTitleMaxHeight", "22", NULL, &wPreferences.menu_title_max_height, getInt, setClearance, + NULL, NULL}, + {"MenuTextExtendSpace", DEF_MENU_TEXT_EXTEND_SPACE, NULL, &wPreferences.menu_text_clearance, + getInt, setClearance, NULL, NULL}, + {"MenuTitleFont", DEF_MENU_TITLE_FONT, NULL, NULL, getFont, setMenuTitleFont, NULL, NULL}, + {"MenuTextFont", DEF_MENU_ENTRY_FONT, NULL, NULL, getFont, setMenuTextFont, NULL, NULL}, + {"IconTitleFont", DEF_ICON_TITLE_FONT, NULL, NULL, getFont, setIconTitleFont, NULL, NULL}, + {"ClipTitleFont", DEF_CLIP_TITLE_FONT, NULL, NULL, getFont, setClipTitleFont, NULL, NULL}, + {"ShowClipTitle", "YES", NULL, &wPreferences.show_clip_title, getBool, NULL, NULL, NULL}, + {"LargeDisplayFont", DEF_WORKSPACE_NAME_FONT, NULL, NULL, getFont, setLargeDisplayFont, NULL, + NULL}, + {"HighlightColor", "white", NULL, NULL, getColor, setHightlight, NULL, NULL}, + {"HighlightTextColor", "black", NULL, NULL, getColor, setHightlightText, NULL, NULL}, + {"ClipTitleColor", "black", (void *)CLIP_NORMAL, NULL, getColor, setClipTitleColor, NULL, NULL}, + {"CClipTitleColor", "\"#454045\"", (void *)CLIP_COLLAPSED, NULL, getColor, setClipTitleColor, + NULL, NULL}, + {"FTitleColor", "white", (void *)WS_FOCUSED, NULL, getColor, setWTitleColor, NULL, NULL}, + {"PTitleColor", "white", (void *)WS_PFOCUSED, NULL, getColor, setWTitleColor, NULL, NULL}, + {"UTitleColor", "black", (void *)WS_UNFOCUSED, NULL, getColor, setWTitleColor, NULL, NULL}, + {"FTitleBack", "(solid, black)", NULL, NULL, getTexture, setFTitleBack, NULL, NULL}, + {"PTitleBack", "(solid, \"#555555\")", NULL, NULL, getTexture, setPTitleBack, NULL, NULL}, + {"UTitleBack", "(solid, \"#aaaaaa\")", NULL, NULL, getTexture, setUTitleBack, NULL, NULL}, + {"ResizebarBack", "(solid, \"#aaaaaa\")", NULL, NULL, getTexture, setResizebarBack, NULL, NULL}, + {"MenuTitleColor", "white", NULL, NULL, getColor, setMenuTitleColor, NULL, NULL}, + {"MenuTextColor", "black", NULL, NULL, getColor, setMenuTextColor, NULL, NULL}, + {"MenuDisabledColor", "\"#555555\"", NULL, NULL, getColor, setMenuDisabledColor, NULL, NULL}, + {"MenuTitleBack", "(solid, black)", NULL, NULL, getTexture, setMenuTitleBack, NULL, NULL}, + {"MenuTextBack", "(solid, \"#aaaaaa\")", NULL, NULL, getTexture, setMenuTextBack, NULL, NULL}, + {"IconTitleColor", "white", NULL, NULL, getColor, setIconTitleColor, NULL, NULL}, + {"IconTitleBack", "black", NULL, NULL, getColor, setIconTitleBack, NULL, NULL}, + {"SwitchPanelImages", "(swtile.png, swback.png, 30, 40)", &wPreferences, NULL, getPropList, + setSwPOptions, NULL, NULL}, + {"ModifierKeyLabels", + "(\"Shift+\", \"Control+\", \"Alt+\", \"Mod2+\", \"Mod3+\", \"Super+\", \"Mod5+\")", + &wPreferences, NULL, getPropList, setModifierKeyLabels, NULL, NULL}, + {"FrameBorderWidth", "1", NULL, NULL, getInt, setFrameBorderWidth, NULL, NULL}, + {"FrameBorderColor", "black", NULL, NULL, getColor, setFrameBorderColor, NULL, NULL}, + {"FrameFocusedBorderColor", "black", NULL, NULL, getColor, setFrameFocusedBorderColor, NULL, + NULL}, + {"FrameSelectedBorderColor", "white", NULL, NULL, getColor, setFrameSelectedBorderColor, NULL, + NULL}, + {"WorkspaceMapBack", "(solid, black)", NULL, NULL, getTexture, setWorkspaceMapBackground, NULL, + NULL}, + + /* --- Key bindings --- */ + + {"CommandModifierKey", "Alt", NULL, &wPreferences.cmd_modifier_mask, getModMask, NULL, NULL, + NULL}, + {"AlternateModifierKey", "Super", NULL, &wPreferences.alt_modifier_mask, getAltModMask, NULL, + NULL, NULL}, + /* Dock and Icon Yard */ + /* {"DockHideShowKey", "\"Alternate+D\"", (void *)WKBD_DOCKHIDESHOW, NULL, getKeybind, + setKeyGrab, NULL, NULL}, */ + /* {"IconYardHideShowKey", "\"Alternate+Y\"", (void *)WKBD_YARDHIDESHOW, NULL, getKeybind, + setKeyGrab, NULL, NULL}, */ + /* Window Resizing */ + /* {"MaximusKey", "\"Super+KP_5\"", (void *)WKBD_MAXIMUS, NULL, getKeybind, setKeyGrab, NULL, + NULL}, */ + /* {"ShadeKey", "\"Alternate+KP_Subtract\"", (void *)WKBD_SHADE, NULL, getKeybind, setKeyGrab, + NULL, NULL}, */ + /* {"MaximizeKey", "\"Alternate+KP_Add\"", (void *)WKBD_MAXIMIZE, NULL, getKeybind, setKeyGrab, + NULL, NULL}, */ + /* {"VMaximizeKey", "\"Alternate+Up\"", (void *)WKBD_VMAXIMIZE, NULL, getKeybind, setKeyGrab, + NULL, NULL}, */ + /* {"HMaximizeKey", "\"Alternate+Right\"", (void *)WKBD_HMAXIMIZE, NULL, getKeybind, setKeyGrab, + NULL, NULL}, */ + /* {"LHMaximizeKey", "\"Alternate+KP_4\"", (void *)WKBD_LHMAXIMIZE, NULL, getKeybind, + setKeyGrab, NULL, NULL}, */ + /* {"RHMaximizeKey", "\"Alternate+KP_6\"", (void *)WKBD_RHMAXIMIZE, NULL, getKeybind, + setKeyGrab, NULL, NULL}, */ + /* {"THMaximizeKey", "\"Alternate+KP_8\"", (void *)WKBD_THMAXIMIZE, NULL, getKeybind, + setKeyGrab, NULL, NULL}, */ + /* {"BHMaximizeKey", "\"Alternate+KP_2\"", (void *)WKBD_BHMAXIMIZE, NULL, getKeybind, + setKeyGrab, NULL, NULL}, */ + /* {"LTCMaximizeKey", "\"Alternate+KP_7\"", (void *)WKBD_LTCMAXIMIZE, NULL, getKeybind, + setKeyGrab, NULL, NULL}, */ + /* {"RTCMaximizeKey", "\"Alternate+KP_9\"", (void *)WKBD_RTCMAXIMIZE, NULL, getKeybind, + setKeyGrab, NULL, NULL}, */ + /* {"LBCMaximizeKey", "\"Alternate+KP_1\"", (void *)WKBD_LBCMAXIMIZE, NULL, getKeybind, + setKeyGrab, NULL, NULL}, */ + /* {"RBCMaximizeKey", "\"Alternate+KP_3\"", (void *)WKBD_RBCMAXIMIZE, NULL, getKeybind, + setKeyGrab, NULL, NULL}, */ + /* Window Ordering */ + /* {"CloseKey", "\"Command+w\"", (void *)WKBD_CLOSE, NULL, getKeybind, setKeyGrab, NULL, NULL}, + */ + /* {"HideKey", "\"Command+h\"", (void *)WKBD_HIDE, NULL, getKeybind, setKeyGrab, NULL, NULL}, */ + /* {"HideOthersKey", "\"Command+H\"", (void *)WKBD_HIDE_OTHERS, NULL, getKeybind, setKeyGrab, + NULL, NULL}, */ + /* {"MiniaturizeKey", "\"Command+m\"", (void *)WKBD_MINIATURIZE, NULL, getKeybind, setKeyGrab, + NULL, NULL}, */ + /* {"MinimizeAllKey", "\"Command+M\"", (void *)WKBD_MINIMIZEALL, NULL, getKeybind, setKeyGrab, + NULL, NULL}, */ + /* Focus switch */ + /* {"RaiseKey", "\"Command+Up\"", (void *)WKBD_RAISE, NULL, getKeybind, setKeyGrab, NULL, NULL}, + */ + /* {"LowerKey", "\"Command+Down\"", (void *)WKBD_LOWER, NULL, getKeybind, setKeyGrab, NULL, + NULL}, */ + {"FocusNextKey", "\"Command+Tab\"", (void *)WKBD_FOCUSNEXT, NULL, getKeybind, setKeyGrab, NULL, + NULL}, + {"FocusPrevKey", "\"Command+Shift+Tab\"", (void *)WKBD_FOCUSPREV, NULL, getKeybind, setKeyGrab, + NULL, NULL}, + {"GroupNextKey", "\"Command+grave\"", (void *)WKBD_GROUPNEXT, NULL, getKeybind, setKeyGrab, + NULL, NULL}, + {"GroupPrevKey", "\"Command+Shift+grave\"", (void *)WKBD_GROUPPREV, NULL, getKeybind, + setKeyGrab, NULL, NULL}, + /* Workspaces */ + {"NextWorkspaceKey", "\"Control+Right\"", (void *)WKBD_NEXT_DESKTOP, NULL, getKeybind, + setKeyGrab, NULL, NULL}, + {"PrevWorkspaceKey", "\"Control+Left\"", (void *)WKBD_PREV_DESKTOP, NULL, getKeybind, + setKeyGrab, NULL, NULL}, + {"LastWorkspaceKey", "None", (void *)WKBD_LAST_DESKTOP, NULL, getKeybind, setKeyGrab, NULL, + NULL}, + {"Desktop1Key", "\"Control+1\"", (void *)WKBD_DESKTOP_1, NULL, getKeybind, setKeyGrab, NULL, + NULL}, + {"Desktop2Key", "\"Control+2\"", (void *)WKBD_DESKTOP_2, NULL, getKeybind, setKeyGrab, NULL, + NULL}, + {"Desktop3Key", "\"Control+3\"", (void *)WKBD_DESKTOP_3, NULL, getKeybind, setKeyGrab, NULL, + NULL}, + {"Desktop4Key", "\"Control+4\"", (void *)WKBD_DESKTOP_4, NULL, getKeybind, setKeyGrab, NULL, + NULL}, + {"Desktop5Key", "\"Control+5\"", (void *)WKBD_DESKTOP_5, NULL, getKeybind, setKeyGrab, NULL, + NULL}, + {"Desktop6Key", "\"Control+6\"", (void *)WKBD_DESKTOP_6, NULL, getKeybind, setKeyGrab, NULL, + NULL}, + {"Desktop7Key", "\"Control+7\"", (void *)WKBD_DESKTOP_7, NULL, getKeybind, setKeyGrab, NULL, + NULL}, + {"Desktop8Key", "\"Control+8\"", (void *)WKBD_DESKTOP_8, NULL, getKeybind, setKeyGrab, NULL, + NULL}, + {"Desktop9Key", "\"Control+9\"", (void *)WKBD_DESKTOP_9, NULL, getKeybind, setKeyGrab, NULL, + NULL}, + {"Desktop10Key", "\"Control+0\"", (void *)WKBD_DESKTOP_10, NULL, getKeybind, setKeyGrab, NULL, + NULL}, + + {"WindowRelaunchKey", "None", (void *)WKBD_RELAUNCH, NULL, getKeybind, setKeyGrab, NULL, NULL}, + + /* --- Mouse cursors --- */ + {"NormalCursor", "(builtin, left_ptr)", (void *)WCUR_ROOT, NULL, getCursor, setCursor, NULL, + NULL}, + {"ArrowCursor", "(builtin, left_ptr)", (void *)WCUR_ARROW, NULL, getCursor, setCursor, NULL, + NULL}, + {"ResizeCursor", "(builtin, sizing)", (void *)WCUR_RESIZE, NULL, getCursor, setCursor, NULL, + NULL}, + {"WaitCursor", "(builtin, watch)", (void *)WCUR_WAIT, NULL, getCursor, setCursor, NULL, NULL}, + {"QuestionCursor", "(builtin, question_arrow)", (void *)WCUR_QUESTION, NULL, getCursor, + setCursor, NULL, NULL}, + {"TextCursor", "(builtin, xterm)", (void *)WCUR_TEXT, NULL, getCursor, setCursor, NULL, NULL}, + {"SelectCursor", "(builtin, cross)", (void *)WCUR_SELECT, NULL, getCursor, setCursor, NULL, + NULL}, + {"MoveCursor", "(library, move)", (void *)WCUR_MOVE, NULL, getCursor, setCursor, NULL, NULL}, + {"TopLeftResizeCursor", "(library, bd_double_arrow)", (void *)WCUR_TOPLEFTRESIZE, NULL, + getCursor, setCursor, NULL, NULL}, + {"TopRightResizeCursor", "(library, fd_double_arrow)", (void *)WCUR_TOPRIGHTRESIZE, NULL, + getCursor, setCursor, NULL, NULL}, + {"BottomLeftResizeCursor", "(library, fd_double_arrow)", (void *)WCUR_BOTTOMLEFTRESIZE, NULL, + getCursor, setCursor, NULL, NULL}, + {"BottomRightResizeCursor", "(library, bd_double_arrow)", (void *)WCUR_BOTTOMRIGHTRESIZE, NULL, + getCursor, setCursor, NULL, NULL}, + {"VerticalResizeCursor", "(library, wm_v_double_arrow)", (void *)WCUR_VERTICALRESIZE, NULL, + getCursor, setCursor, NULL, NULL}, + {"HorizontalResizeCursor", "(library, wm_h_double_arrow)", (void *)WCUR_HORIZONRESIZE, NULL, + getCursor, setCursor, NULL, NULL}, + {"UpResizeCursor", "(library, wm_up_arrow)", (void *)WCUR_UPRESIZE, NULL, getCursor, setCursor, + NULL, NULL}, + {"DownResizeCursor", "(library, wm_down_arrow)", (void *)WCUR_DOWNRESIZE, NULL, getCursor, + setCursor, NULL, NULL}, + {"LeftResizeCursor", "(library, wm_left_arrow)", (void *)WCUR_LEFTRESIZE, NULL, getCursor, + setCursor, NULL, NULL}, + {"RightResizeCursor", "(library, wm_right_arrow)", (void *)WCUR_RIGHTRESIZE, NULL, getCursor, + setCursor, NULL, NULL}, + {"DialogHistoryLines", "500", NULL, &wPreferences.history_lines, getInt, NULL, NULL, NULL}, + {"CycleActiveHeadOnly", "NO", NULL, &wPreferences.cycle_active_head_only, getBool, NULL, NULL, + NULL}, + {"CycleIgnoreMinimized", "NO", NULL, &wPreferences.cycle_ignore_minimized, getBool, NULL, NULL, + NULL}}; + /* set `plkey` and `plvalue` fields of entries in `optionList` and `staticOptionList` */ static void _initializeOptionLists(void) @@ -623,6 +735,8 @@ static void _updateDomain(WDDomain *domain, Bool shouldNotify) return; } + WMLogWarning("Updating domain %@...", domain->name); + #ifdef HAVE_INOTIFY wDefaultsShouldTrackChanges(domain, false); #endif @@ -636,8 +750,8 @@ static void _updateDomain(WDDomain *domain, Bool shouldNotify) WMLogError("Domain %@ of defaults database is corrupted!", domain->name); } else { - if ((scr = wDefaultScreen())) { - wDefaultsRead(scr, dict, shouldNotify); + if ((scr = wDefaultScreen()) && CFStringCompare(domain->name, CFSTR("WM"), 0) == 0) { + wDefaultsReadPreferences(scr, dict, shouldNotify); } if (domain->dictionary) { CFRelease(domain->dictionary); @@ -663,11 +777,14 @@ static void _updateDomain(WDDomain *domain, Bool shouldNotify) static WDDomain *_domainForWatchDescriptor(int wd) { - if (wd == w_global.domain.wm->inotify_watch) { - return w_global.domain.wm; + if (wd == w_global.domain.wm_preferences->inotify_watch) { + return w_global.domain.wm_preferences; } - if (wd == w_global.domain.window_attr->inotify_watch) { - return w_global.domain.window_attr; + if (wd == w_global.domain.wm_state->inotify_watch) { + return w_global.domain.wm_state; + } + if (wd == w_global.domain.window_attrs->inotify_watch) { + return w_global.domain.window_attrs; } return NULL; @@ -689,7 +806,7 @@ static void _processWatchEvents(CFFileDescriptorRef fdref, CFOptionFlags callBac eventQLength = read(w_global.inotify.fd_event_queue, buff, sizeof(buff)); if (eventQLength < 0) { - WMLogWarning(_("read problem when trying to get INotify event: %s"), strerror(errno)); + WMLogWarning("read problem when trying to get INotify event: %s", strerror(errno)); return; } @@ -699,31 +816,32 @@ static void _processWatchEvents(CFFileDescriptorRef fdref, CFOptionFlags callBac domain = _domainForWatchDescriptor(pevent->wd); if (!domain) { - WMLogWarning(_("inotify: ignore event for domain that is not tracked anymore.")); + WMLogWarning("inotify: ignore event for domain that is not tracked anymore."); goto next_event; } if (pevent->mask & IN_MODIFY) { - WMLogWarning(_("inotify: defaults domain has been modified. Rereading defaults database.")); + WMLogWarning("inotify: defaults domain has been modified. Rereading defaults database."); /* _updateDomain(domain); */ wDefaultsUpdateDomainsIfNeeded(NULL); } if (pevent->mask & IN_MOVE_SELF) { - WMLogWarning(_("inotify: %i defaults domain has been moved."), pevent->wd); + WMLogWarning("inotify: %i defaults domain has been moved.", pevent->wd); /* _updateDomain(domain); */ wDefaultsUpdateDomainsIfNeeded(NULL); } if (pevent->mask & IN_DELETE_SELF) { - WMLogWarning(_("inotify: %i defaults domain has been deleted!"), pevent->wd); + WMLogWarning("inotify: %i defaults domain has been deleted!", pevent->wd); /* _updateDomain(domain); */ wDefaultsUpdateDomainsIfNeeded(NULL); } if (pevent->mask & IN_UNMOUNT) { - WMLogWarning(_("inotify: the unit containing the defaults database has" - " been unmounted. Setting --static mode." " Any changes will not be saved.")); + WMLogWarning("inotify: the unit containing the defaults database has" + " been unmounted. Setting --static mode." + " Any changes will not be saved."); wDefaultsShouldTrackChanges(domain, false); wPreferences.flags.noupdates = 1; @@ -851,7 +969,7 @@ WDDomain *wDefaultsInitDomain(const char *domain_name, Bool shouldTrackChanges) // Called from startup.c // Apply `plvalue` from `dict` to appropriate `entry->addr` specified in `staticOptionList` -void wDefaultsReadStatic(CFMutableDictionaryRef dict) +void wDefaultsReadStaticPreferences(CFMutableDictionaryRef dict) { CFTypeRef plvalue; WDefaultEntry *entry; @@ -885,25 +1003,27 @@ void wDefaultsReadStatic(CFMutableDictionaryRef dict) } } -// Apply `plvalue` from `new_dict` to appropriate `entry->addr` specified in `optionList` -// Load wPreferences with values loaded from WM.plist - set default values otherwise. -// -// TODO: Currently `w_global.domain.wm->dictionary` is a memory rep of the WMState.plist file. -// So, this function has no connection to WM.plist file if any exsists. -void wDefaultsRead(WScreen *scr, CFMutableDictionaryRef new_dict, Bool shouldNotify) +// Propagates `optionList` values to `wPreferences`, `WScreen` or other global variable. +// If option exists in `new_dict` - use it instead. +// Usually `new_dict` is a `w_global.domain.wm_preferences->dictionary` which is the in-memory +// representation of WM.plist file. +// +// Function applies `plvalue` from `new_dict` to appropriate `entry->addr` specified in `optionList`. +// `entry->addr` is a wPreferences member or `NULL`. `NULL` means that `entry->update` callback +// sets value to appropriate structure (for example, WScreen) or global variable. +void wDefaultsReadPreferences(WScreen *scr, CFMutableDictionaryRef new_dict, Bool shouldNotify) { + CFDictionaryRef old_dict = NULL; CFTypeRef plvalue = NULL; - CFTypeRef old_value = NULL; + CFTypeRef old_plvalue = NULL; WDefaultEntry *entry; unsigned int i; unsigned int needs_refresh = 0; void *tdata; - CFDictionaryRef old_dict = NULL; - if (w_global.domain.wm_preferences->dictionary != new_dict) + if (w_global.domain.wm_preferences->dictionary != new_dict) { old_dict = w_global.domain.wm_preferences->dictionary; - - needs_refresh = 0; + } for (i = 0; i < wlengthof(optionList); i++) { entry = &optionList[i]; @@ -916,37 +1036,32 @@ void wDefaultsRead(WScreen *scr, CFMutableDictionaryRef new_dict, Bool shouldNot plvalue = NULL; } - if (!old_dict) { - old_value = NULL; + if (old_dict) { + old_plvalue = CFDictionaryGetValue(old_dict, entry->plkey); } else { - old_value = CFDictionaryGetValue(old_dict, entry->plkey); + old_plvalue = NULL; } // No need to hold default value in dictionary - /* WMLogError("Check if default exist: %@", entry->plkey); */ if (plvalue && CFEqual(plvalue, entry->plvalue)) { plvalue = NULL; - // WMLogError("Removing setting equal to default: %@", entry->plkey); CFDictionaryRemoveValue(new_dict, entry->plkey); - // WMLogError("Removed"); } if (!plvalue) { - /* value was deleted from DB. Keep current value */ + // value was deleted from DB. Keep current value plvalue = entry->plvalue; - /* continue; */ - } else if (!old_value) { - /* set value for the 1st time */ - } - else if (CFEqual(plvalue, old_value)) { - /* value was not changed since last time */ + } else if (!old_plvalue) { + // set value for the 1st time + } else if (CFEqual(plvalue, old_plvalue)) { + // value was not changed since last time continue; } if (plvalue) { - /* convert data */ - WMLogWarning("Processing %@", entry->plkey); + // convert data if ((*entry->convert) (scr, entry, plvalue, entry->addr, &tdata)) { + // propagate converted value if (entry->update) { needs_refresh |= (*entry->update) (scr, entry, tdata, entry->extra_data); } @@ -954,8 +1069,6 @@ void wDefaultsRead(WScreen *scr, CFMutableDictionaryRef new_dict, Bool shouldNot } } - WMLogInfo("%@ values: %@ - needs_refresh: %i", w_global.domain.wm_preferences->name, w_global.domain.wm_preferences->dictionary, needs_refresh); - if (shouldNotify && needs_refresh != 0 /* && !scr->flags.startup && !scr->flags.startup2*/) { int foo; @@ -968,8 +1081,8 @@ void wDefaultsRead(WScreen *scr, CFMutableDictionaryRef new_dict, Bool shouldNot foo |= WColorSettings; if (foo) { CFNotificationCenterPostNotification(CFNotificationCenterGetLocalCenter(), - WMDidChangeMenuTitleAppearanceSettings, - (void *)(uintptr_t) foo, NULL, TRUE); + WMDidChangeMenuTitleAppearanceSettings, + (void *)(uintptr_t)foo, NULL, TRUE); } foo = 0; if (needs_refresh & REFRESH_MENU_TEXTURE) @@ -980,8 +1093,8 @@ void wDefaultsRead(WScreen *scr, CFMutableDictionaryRef new_dict, Bool shouldNot foo |= WColorSettings; if (foo) { CFNotificationCenterPostNotification(CFNotificationCenterGetLocalCenter(), - WMDidChangeMenuAppearanceSettings, - (void *)(uintptr_t) foo, NULL, TRUE); + WMDidChangeMenuAppearanceSettings, + (void *)(uintptr_t)foo, NULL, TRUE); } foo = 0; if (needs_refresh & REFRESH_WINDOW_FONT) @@ -992,8 +1105,8 @@ void wDefaultsRead(WScreen *scr, CFMutableDictionaryRef new_dict, Bool shouldNot foo |= WColorSettings; if (foo) { CFNotificationCenterPostNotification(CFNotificationCenterGetLocalCenter(), - WMDidChangeWindowAppearanceSettings, - (void *)(uintptr_t) foo, NULL, TRUE); + WMDidChangeWindowAppearanceSettings, + (void *)(uintptr_t)foo, NULL, TRUE); } if (!(needs_refresh & REFRESH_ICON_TILE)) { foo = 0; @@ -1005,7 +1118,7 @@ void wDefaultsRead(WScreen *scr, CFMutableDictionaryRef new_dict, Bool shouldNot foo |= WTextureSettings; if (foo) { CFNotificationCenterPostNotification(CFNotificationCenterGetLocalCenter(), - WMDidChangeIconAppearanceSettings, + WMDidChangeIconAppearanceSettings, (void *)(uintptr_t)foo, NULL, TRUE); } } @@ -1024,16 +1137,22 @@ void wDefaultsUpdateDomainsIfNeeded(void* arg) WScreen *scr; CFAbsoluteTime time = 0.0; - // ~/Library/Preferences/.NextSpace/WM - time = WMUserDefaultsFileModificationTime(w_global.domain.wm->name, 0); - if (w_global.domain.wm->timestamp < time) { - _updateDomain(w_global.domain.wm, True); + // ~/Library/Preferences/.NextSpace/WM.plist + time = WMUserDefaultsFileModificationTime(w_global.domain.wm_preferences->name, 0); + if (w_global.domain.wm_preferences->timestamp < time) { + _updateDomain(w_global.domain.wm_preferences, True); + } + + // ~/Library/Preferences/.NextSpace/WMState.plist + time = WMUserDefaultsFileModificationTime(w_global.domain.wm_state->name, 0); + if (w_global.domain.wm_preferences->timestamp < time) { + _updateDomain(w_global.domain.wm_preferences, True); } - // ~/Library/Preferences/.NextSpace/WMWindowAttributes - time = WMUserDefaultsFileModificationTime(w_global.domain.window_attr->name, 0); - if (w_global.domain.window_attr->timestamp < time) { - _updateDomain(w_global.domain.window_attr, False); + // ~/Library/Preferences/.NextSpace/WMWindowAttributes.plist + time = WMUserDefaultsFileModificationTime(w_global.domain.window_attrs->name, 0); + if (w_global.domain.window_attrs->timestamp < time) { + _updateDomain(w_global.domain.window_attrs, False); if ((scr = wDefaultScreen())) { _updateApplicationIcons(scr); } diff --git a/Applications/Workspace/WM/defaults.h b/Applications/Workspace/WM/defaults.h index 299125d68..d0fa5af90 100644 --- a/Applications/Workspace/WM/defaults.h +++ b/Applications/Workspace/WM/defaults.h @@ -230,8 +230,8 @@ extern struct WPreferences { } wPreferences; WDDomain *wDefaultsInitDomain(const char *domain_name, Bool shouldTrackChanges); -void wDefaultsReadStatic(CFMutableDictionaryRef dict); -void wDefaultsRead(WScreen *scr, CFMutableDictionaryRef new_dict, Bool shouldNotify); +void wDefaultsReadStaticPreferences(CFMutableDictionaryRef dict); +void wDefaultsReadPreferences(WScreen *scr, CFMutableDictionaryRef new_dict, Bool shouldNotify); void wDefaultsUpdateDomainsIfNeeded(void *arg); #ifdef HAVE_INOTIFY diff --git a/Applications/Workspace/WM/dock.c b/Applications/Workspace/WM/dock.c index ef4ee9623..d953fdd4f 100644 --- a/Applications/Workspace/WM/dock.c +++ b/Applications/Workspace/WM/dock.c @@ -714,7 +714,7 @@ static WAppIcon *mainIconCreate(WScreen *scr, int type, const char *name) icon_desc = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDictionarySetValue(icon_desc, CFSTR("Icon"), CFSTR(APP_ICON)); - CFDictionarySetValue(w_global.domain.window_attr->dictionary, CFSTR("Workspace.GNUstep"), + CFDictionarySetValue(w_global.domain.window_attrs->dictionary, CFSTR("Workspace.GNUstep"), icon_desc); CFRelease(icon_desc); btn = wAppIconCreateForDock(scr, NULL, "Workspace", "GNUstep", TILE_NORMAL); diff --git a/Applications/Workspace/WM/event.c b/Applications/Workspace/WM/event.c index 220a1f12a..993dd23bc 100644 --- a/Applications/Workspace/WM/event.c +++ b/Applications/Workspace/WM/event.c @@ -328,8 +328,8 @@ void WMRunLoop_V0() #ifdef HAVE_INOTIFY /* Track some defaults files for changes */ w_global.inotify.fd_event_queue = -1; - wDefaultsShouldTrackChanges(w_global.domain.wm, true); - wDefaultsShouldTrackChanges(w_global.domain.window_attr, true); + wDefaultsShouldTrackChanges(w_global.domain.wm_preferences, true); + wDefaultsShouldTrackChanges(w_global.domain.window_attrs, true); #else /* Setup defaults files polling */ if (!wPreferences.flags.noupdates) { diff --git a/Applications/Workspace/WM/screen.c b/Applications/Workspace/WM/screen.c index 64aed8b17..1b8d8572d 100644 --- a/Applications/Workspace/WM/screen.c +++ b/Applications/Workspace/WM/screen.c @@ -800,7 +800,8 @@ WScreen *wScreenInit(int screen_number) allocGCs(scr); /* read defaults for this screen */ - wDefaultsRead(scr, w_global.domain.wm_preferences->dictionary, True); + wDefaultsReadPreferences(scr, w_global.domain.wm_preferences->dictionary, True); + fprintf(stderr, "Menu item font is: %s\n", scr->menu_item_font->name); { XColor xcol; diff --git a/Applications/Workspace/WM/startup.c b/Applications/Workspace/WM/startup.c index b2ef4fbc0..b0cc32a73 100644 --- a/Applications/Workspace/WM/startup.c +++ b/Applications/Workspace/WM/startup.c @@ -650,21 +650,28 @@ void wStartUp(Bool defaultScreenOnly) /* set hook for out event dispatcher in WINGs event dispatcher */ WMHookEventHandler(DispatchEvent); - /* initialize defaults stuff */ + /* + Initialize defaults stuff + */ + // Read defaults from WM.plist file. This file may not exist - use hardcoded defults (defaults.c). + // Defaults are propagated into wPreferences, WScreen. w_global.domain.wm_preferences = wDefaultsInitDomain("WM", true); if (!w_global.domain.wm_preferences->dictionary) { WMLogWarning(_("could not read domain \"%s\" from defaults database"), "WMState"); } - w_global.domain.wm = wDefaultsInitDomain("WMState", true); - if (!w_global.domain.wm->dictionary) { - WMLogWarning(_("could not read domain \"%s\" from defaults database"), "WMState"); + // Process defaults that don't change until a restart and are screen independent. + // Were read from WM.plist on previous step. + if (w_global.domain.wm_preferences) { + wDefaultsReadStaticPreferences(w_global.domain.wm_preferences->dictionary); + // WMUserDefaultsWrite(w_global.domain.wm_preferences->dictionary, w_global.domain.wm_preferences->name); + } else { + wDefaultsReadStaticPreferences(NULL); } - /* read defaults that don't change until a restart and are screen independent */ - wDefaultsReadStatic(w_global.domain.wm ? w_global.domain.wm->dictionary : NULL); - if (w_global.domain.wm) { - WMUserDefaultsWrite(w_global.domain.wm->dictionary, w_global.domain.wm->name); + w_global.domain.wm_state = wDefaultsInitDomain("WMState", true); + if (!w_global.domain.wm_state->dictionary) { + WMLogWarning(_("could not read domain \"%s\" from defaults database"), "WMState"); } /* check sanity of some values */ @@ -675,8 +682,8 @@ void wStartUp(Bool defaultScreenOnly) } /* init other domains */ - w_global.domain.window_attr = wDefaultsInitDomain("WMWindowAttributes", true); - if (!w_global.domain.window_attr->dictionary) { + w_global.domain.window_attrs = wDefaultsInitDomain("WMWindowAttributes", true); + if (!w_global.domain.window_attrs->dictionary) { WMLogWarning(_("could not read domain \"%s\" from defaults database"), "WMWindowAttributes"); } diff --git a/Applications/Workspace/WM/window_attributes.c b/Applications/Workspace/WM/window_attributes.c index ec6c6570b..f03710f72 100644 --- a/Applications/Workspace/WM/window_attributes.c +++ b/Applications/Workspace/WM/window_attributes.c @@ -167,8 +167,8 @@ static CFTypeRef get_value_from_instanceclass(const char *value) key = CFStringCreateWithCString(kCFAllocatorDefault, value, kCFStringEncodingUTF8); - if (w_global.domain.window_attr->dictionary) - val = key ? CFDictionaryGetValue(w_global.domain.window_attr->dictionary, key) : NULL; + if (w_global.domain.window_attrs->dictionary) + val = key ? CFDictionaryGetValue(w_global.domain.window_attrs->dictionary, key) : NULL; if (key) CFRelease(key); @@ -245,8 +245,8 @@ void wDefaultFillAttributes(const char *instance, const char *class, WWindowAttr dn = get_value_from_instanceclass(instance); dc = get_value_from_instanceclass(class); - if ((w_global.domain.window_attr->dictionary) && (useGlobalDefault)) - da = CFDictionaryGetValue(w_global.domain.window_attr->dictionary, AnyWindow); + if ((w_global.domain.window_attrs->dictionary) && (useGlobalDefault)) + da = CFDictionaryGetValue(w_global.domain.window_attrs->dictionary, AnyWindow); /* get the data */ value = get_value(dw, dc, dn, da, ANoTitlebar, No, useGlobalDefault); @@ -338,7 +338,7 @@ static CFTypeRef get_generic_value(const char *instance, const char *class, CFSt /* Search the icon name using class and instance */ if (class && instance) { key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s.%s"), instance, class); - dict = CFDictionaryGetValue(w_global.domain.window_attr->dictionary, key); + dict = CFDictionaryGetValue(w_global.domain.window_attrs->dictionary, key); CFRelease(key); if (dict) { @@ -350,7 +350,7 @@ static CFTypeRef get_generic_value(const char *instance, const char *class, CFSt if (!value && instance) { key = CFStringCreateWithCString(kCFAllocatorDefault, instance, kCFStringEncodingUTF8); - dict = CFDictionaryGetValue(w_global.domain.window_attr->dictionary, key); + dict = CFDictionaryGetValue(w_global.domain.window_attrs->dictionary, key); CFRelease(key); if (dict) { @@ -362,7 +362,7 @@ static CFTypeRef get_generic_value(const char *instance, const char *class, CFSt if (!value && class) { key = CFStringCreateWithCString(kCFAllocatorDefault, class, kCFStringEncodingUTF8); - dict = CFDictionaryGetValue(w_global.domain.window_attr->dictionary, key); + dict = CFDictionaryGetValue(w_global.domain.window_attrs->dictionary, key); CFRelease(key); if (dict) @@ -372,7 +372,7 @@ static CFTypeRef get_generic_value(const char *instance, const char *class, CFSt /* Search the default icon name - See default_icon argument! */ if (!value && default_icon) { /* AnyWindow is "*" - see wdefaults.c */ - dict = CFDictionaryGetValue(w_global.domain.window_attr->dictionary, AnyWindow); + dict = CFDictionaryGetValue(w_global.domain.window_attrs->dictionary, AnyWindow); if (dict) value = CFDictionaryGetValue(dict, option); @@ -502,7 +502,7 @@ int wDefaultGetStartWorkspace(WScreen *scr, const char *instance, const char *cl int w; const char *tmp; - if (!w_global.domain.window_attr->dictionary) + if (!w_global.domain.window_attrs->dictionary) return -1; value = get_generic_value(instance, class, AStartWorkspace, True); @@ -527,7 +527,7 @@ const char *wDefaultGetIconFile(const char *instance, const char *class, Bool de CFTypeRef value; const char *tmp; - if (!w_global.domain.window_attr || !w_global.domain.window_attr->dictionary) + if (!w_global.domain.window_attrs || !w_global.domain.window_attrs->dictionary) return NULL; value = get_generic_value(instance, class, AIcon, default_icon); @@ -542,7 +542,7 @@ const char *wDefaultGetIconFile(const char *instance, const char *class, Bool de void wDefaultChangeIcon(const char *instance, const char *class, const char *file) { - WDDomain *db = w_global.domain.window_attr; + WDDomain *db = w_global.domain.window_attrs; CFMutableDictionaryRef dict = db->dictionary; CFMutableDictionaryRef icon_entry = NULL; CFMutableDictionaryRef attrs = NULL; @@ -629,11 +629,11 @@ void wDefaultPurgeInfo(const char *instance, const char *class) CFDictionaryRef dict; key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s.%s"), instance, class); - dict = CFDictionaryGetValue(w_global.domain.window_attr->dictionary, key); + dict = CFDictionaryGetValue(w_global.domain.window_attrs->dictionary, key); if (dict) { - CFDictionaryRemoveValue(w_global.domain.window_attr->dictionary, key); - WMUserDefaultsWrite(w_global.domain.window_attr->dictionary, w_global.domain.window_attr->name); + CFDictionaryRemoveValue(w_global.domain.window_attrs->dictionary, key); + WMUserDefaultsWrite(w_global.domain.window_attrs->dictionary, w_global.domain.window_attrs->name); } CFRelease(key); From e5592bff2140040f1f756e5d56a450d5799cc682 Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Wed, 25 Oct 2023 19:22:31 +0300 Subject: [PATCH 46/67] Workspace: when reading preferences file create a copy of CFDictionary; cleanup. --- Applications/Workspace/WM/defaults.c | 73 +++++++++++++++------------- 1 file changed, 38 insertions(+), 35 deletions(-) diff --git a/Applications/Workspace/WM/defaults.c b/Applications/Workspace/WM/defaults.c index da95a1674..f89e04baf 100644 --- a/Applications/Workspace/WM/defaults.c +++ b/Applications/Workspace/WM/defaults.c @@ -735,38 +735,38 @@ static void _updateDomain(WDDomain *domain, Bool shouldNotify) return; } - WMLogWarning("Updating domain %@...", domain->name); - #ifdef HAVE_INOTIFY wDefaultsShouldTrackChanges(domain, false); #endif + WMLogWarning("Updating domain %@...", domain->name); /* User dictionary */ dict = (CFMutableDictionaryRef)WMUserDefaultsRead(domain->name, false); + if (CFStringCompare(domain->name, CFSTR("WM"), 0) == 0) { + WMLogWarning("Updating domain %@ with dictionary: %@", domain->name, dict); + } if (dict) { - if (CFGetTypeID(dict) != CFDictionaryGetTypeID()) { - CFRelease(dict); - dict = NULL; - WMLogError("Domain %@ of defaults database is corrupted!", domain->name); - } - else { + if (CFGetTypeID(dict) == CFDictionaryGetTypeID()) { if ((scr = wDefaultScreen()) && CFStringCompare(domain->name, CFSTR("WM"), 0) == 0) { wDefaultsReadPreferences(scr, dict, shouldNotify); } if (domain->dictionary) { CFRelease(domain->dictionary); } - domain->dictionary = dict; + domain->dictionary = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, dict); + } else { + WMLogError("Domain %@ of defaults database is corrupted!", domain->name); } - } - else { + CFRelease(dict); + dict = NULL; + } else { WMLogError("Could not load domain %@. It is not dictionary!", domain->name); if (domain->dictionary) { WMLogError("Write from memory to path %@.", domain->path); WMUserDefaultsWrite(domain->dictionary, domain->name); } } - + domain->timestamp = WMUserDefaultsFileModificationTime(domain->name, 0); #ifdef HAVE_INOTIFY wDefaultsShouldTrackChanges(domain, true); @@ -816,31 +816,29 @@ static void _processWatchEvents(CFFileDescriptorRef fdref, CFOptionFlags callBac domain = _domainForWatchDescriptor(pevent->wd); if (!domain) { - WMLogWarning("inotify: ignore event for domain that is not tracked anymore."); + WMLogWarning("inotify [descriptor %i]: ignore event for domain that is not tracked anymore.", + pevent->wd); goto next_event; } if (pevent->mask & IN_MODIFY) { - WMLogWarning("inotify: defaults domain has been modified. Rereading defaults database."); - /* _updateDomain(domain); */ + WMLogWarning("inotify [descriptor %i]: defaults domain has been modified.", pevent->wd); wDefaultsUpdateDomainsIfNeeded(NULL); } if (pevent->mask & IN_MOVE_SELF) { - WMLogWarning("inotify: %i defaults domain has been moved.", pevent->wd); - /* _updateDomain(domain); */ + WMLogWarning("inotify [descriptor %i]: defaults domain has been moved.", pevent->wd); wDefaultsUpdateDomainsIfNeeded(NULL); } if (pevent->mask & IN_DELETE_SELF) { - WMLogWarning("inotify: %i defaults domain has been deleted!", pevent->wd); - /* _updateDomain(domain); */ + WMLogWarning("inotify [descriptor %i]: defaults domain has been deleted.", pevent->wd); wDefaultsUpdateDomainsIfNeeded(NULL); } if (pevent->mask & IN_UNMOUNT) { WMLogWarning("inotify: the unit containing the defaults database has" - " been unmounted. Setting --static mode." + " been unmounted. Disabling tracking changes mode." " Any changes will not be saved."); wDefaultsShouldTrackChanges(domain, false); @@ -851,7 +849,7 @@ static void _processWatchEvents(CFFileDescriptorRef fdref, CFOptionFlags callBac /* move to next event in the buffer */ i += sizeof(struct inotify_event) + pevent->len; } - + CFFileDescriptorEnableCallBacks(fdref, kCFFileDescriptorReadCallBack); } @@ -920,6 +918,7 @@ WDDomain *wDefaultsInitDomain(const char *domain_name, Bool shouldTrackChanges) { WDDomain *domain; static int inited = 0; + CFMutableDictionaryRef dict; if (!inited) { inited = 1; @@ -933,22 +932,24 @@ WDDomain *wDefaultsInitDomain(const char *domain_name, Bool shouldTrackChanges) domain->name = CFStringCreateWithCString(kCFAllocatorDefault, domain_name, kCFStringEncodingUTF8); domain->inotify_watch = -1; - domain->dictionary = (CFMutableDictionaryRef)WMUserDefaultsRead(domain->name, true); - if (domain->dictionary) { - if ((CFGetTypeID(domain->dictionary) != CFDictionaryGetTypeID())) { - CFRelease(domain->dictionary); + // Initializing domain->dictionary + dict = (CFMutableDictionaryRef)WMUserDefaultsRead(domain->name, true); + if (dict) { + if ((CFGetTypeID(dict) != CFDictionaryGetTypeID())) { + CFRelease(dict); domain->dictionary = NULL; - WMLogError(_("domain %s (%s) of defaults database is corrupted!"), domain_name, - WMUserDefaultsGetCString(CFURLGetString(domain->path), kCFStringEncodingUTF8)); + WMLogError("domain %s (%@) of defaults database is corrupted!", domain_name, + CFURLGetString(domain->path)); } - } - else { + domain->dictionary = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, dict); + CFRelease(dict); + } else { WMLogError("creating empty domain: %@", domain->name); domain->dictionary = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } - + if (domain->dictionary && WMUserDefaultsWrite(domain->dictionary, domain->name)) { CFURLRef osURL; @@ -1021,17 +1022,19 @@ void wDefaultsReadPreferences(WScreen *scr, CFMutableDictionaryRef new_dict, Boo unsigned int needs_refresh = 0; void *tdata; + WMLogWarning("Reading preferences from WM.plist...."); + if (w_global.domain.wm_preferences->dictionary != new_dict) { old_dict = w_global.domain.wm_preferences->dictionary; } + WMLogWarning("WindowTitleFont from new_dict %@", CFDictionaryGetValue(new_dict, CFSTR("WindowTitleFont"))); + for (i = 0; i < wlengthof(optionList); i++) { entry = &optionList[i]; if (new_dict) { plvalue = CFDictionaryGetValue(new_dict, entry->plkey); - if (plvalue) - WMLogWarning("Got value: %@ for %@", plvalue, entry->plkey); } else { plvalue = NULL; } @@ -1131,7 +1134,7 @@ void wDefaultsReadPreferences(WScreen *scr, CFMutableDictionaryRef new_dict, Boo } // Update in-memory representaion of user defaults. -// Also used as CFTimer callback. +// Also used as CFTimer callback - that's why argument exists. void wDefaultsUpdateDomainsIfNeeded(void* arg) { WScreen *scr; @@ -1145,8 +1148,8 @@ void wDefaultsUpdateDomainsIfNeeded(void* arg) // ~/Library/Preferences/.NextSpace/WMState.plist time = WMUserDefaultsFileModificationTime(w_global.domain.wm_state->name, 0); - if (w_global.domain.wm_preferences->timestamp < time) { - _updateDomain(w_global.domain.wm_preferences, True); + if (w_global.domain.wm_state->timestamp < time) { + _updateDomain(w_global.domain.wm_state, True); } // ~/Library/Preferences/.NextSpace/WMWindowAttributes.plist From 33392b99d182c32f9ad626c0b226e0ff02ba9636 Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Thu, 26 Oct 2023 18:40:03 +0300 Subject: [PATCH 47/67] fixed initializing and tracking changes of WM defaults. Disabled tracking changes of WM.plist with inotify - Preferences app sends notification when this file was changed. WM observes this notification with WM's notification center (notification between NSGlobalNotificationCenter and CFNotificationCenter dispatched by WMNotificationCenter). --- Applications/Preferences/Modules/Font/Font.m | 71 ++++++----- Applications/Workspace/WM/WM.h | 3 +- Applications/Workspace/WM/defaults.c | 112 +++++++++++------- Applications/Workspace/WM/defaults.h | 1 + Applications/Workspace/WM/event.c | 1 - Applications/Workspace/WM/screen.c | 1 - Applications/Workspace/WM/startup.c | 14 ++- Applications/Workspace/WMNotificationCenter.m | 2 +- 8 files changed, 116 insertions(+), 89 deletions(-) diff --git a/Applications/Preferences/Modules/Font/Font.m b/Applications/Preferences/Modules/Font/Font.m index 1aa15fbc8..bf1820818 100644 --- a/Applications/Preferences/Modules/Font/Font.m +++ b/Applications/Preferences/Modules/Font/Font.m @@ -50,24 +50,24 @@ - (void) updateUI; @implementation Font (Private) -static NSBundle *bundle = nil; -static NSUserDefaults *defaults = nil; +static NSBundle *bundle = nil; +static NSUserDefaults *defaults = nil; static NSMutableDictionary *domain = nil; -static NSPanel *fontPanel = nil; +static NSPanel *fontPanel = nil; -// + userFontOfSize: [Application Font] +// + userFontOfSize: [Application Font] // + userFixedPitchFontOfSize: [Fixed Pitch Font] -// + systemFontOfSize: [System Font] -// + boldSystemFontOfSize: [Bold System Font] +// + systemFontOfSize: [System Font] +// + boldSystemFontOfSize: [Bold System Font] // ========================== MACOSX, GS_API_LATEST =========================== -// + toolTipsFontOfSize: [System Font:11] -// + menuFontOfSize: [System Font] -// + messageFontOfSize: [System Font:14] -// + controlContentFontOfSize: [System Font] -// + labelFontOfSize: [System Font] -// + titleBarFontOfSize: [Bold System Font] -// + menuBarFontOfSize: [Bold System Font] -// + paletteFontOfSize: [Bold System Font] +// + toolTipsFontOfSize: [System Font:11] +// + menuFontOfSize: [System Font] +// + messageFontOfSize: [System Font:14] +// + controlContentFontOfSize: [System Font] +// + labelFontOfSize: [System Font] +// + titleBarFontOfSize: [Bold System Font] +// + menuBarFontOfSize: [Bold System Font] +// + paletteFontOfSize: [Bold System Font] // ========================== MACOSX, GS_API_LATEST =========================== static NSMutableDictionary *defaultValues(void) @@ -198,7 +198,6 @@ - (void)setWMFont:(NSFont *)font key:(NSString *)key NSString *wmDefaultsPath = WWMDefaultsPath(); NSMutableDictionary *wmDefaults; NSMutableString *value; - NSDistributedNotificationCenter *center = [NSDistributedNotificationCenter defaultCenter]; if (![[NSFileManager defaultManager] fileExistsAtPath:wmDefaultsPath]) { /* TODO: WM doesn't track WM.plist changes if it doesn't exist. @@ -206,16 +205,15 @@ - (void)setWMFont:(NSFont *)font key:(NSString *)key notification center (WM should handle this notification and reread file). */ NSLog(@"[Font] can't find existing WM defaults database! Creating new..."); wmDefaults = [NSMutableDictionary new]; - } - else { + } else { wmDefaults = [[NSMutableDictionary alloc] initWithContentsOfFile:wmDefaultsPath]; } - + // Convert font name into the FontConfig format. value = [NSMutableString stringWithFormat:@"%@:postscriptname=%@:pixelsize=%.0f:antialias=%@", [font familyName], [font fontName], [font pointSize], [enableAntiAliasingButton state] ? @"true" : @"false"]; - NSLog(@"[Font] set WM font %@ = `%@` -> (%@)", key, value, wmDefaultsPath); + // NSLog(@"[Font] set WM font %@ = `%@` -> (%@)", key, value, wmDefaultsPath); [wmDefaults setObject:value forKey:key]; [wmDefaults writeToFile:wmDefaultsPath atomically:YES]; @@ -387,28 +385,25 @@ - (IBAction)enableAntiAliasingChanged:(id)sender - (void)changeFont:(id)sender { - NSString *fontName, *fontKey; - CGFloat fontSize; + NSString *fontName, *fontKey; + CGFloat fontSize; NSFontManager *fontManager = [NSFontManager sharedFontManager]; - NSFont *font; + NSFont *font; font = [fontManager convertFont:[fontExampleTextView font]]; fontName = [font fontName]; fontSize = [font pointSize]; - fontKey = [fontCategories - objectForKey:[fontCategoryPopUp titleOfSelectedItem]]; + fontKey = [fontCategories objectForKey:[fontCategoryPopUp titleOfSelectedItem]]; - if ([fontKey isEqualToString:@"NSUserFont"]) { // Application + if ([fontKey isEqualToString:@"NSUserFont"]) { // Application // NSUserFont, NSUserFontSize=12 setStringDefault(fontName, @"NSUserFont"); setFloatDefault(fontSize, @"NSUserFontSize"); - } - else if ([fontKey isEqualToString:@"NSUserFixedPitchFont"]) {// Fixed Pitch + } else if ([fontKey isEqualToString:@"NSUserFixedPitchFont"]) { // Fixed Pitch // NSUserFixedPitchFont, NSUserFixedPitchFontSize setStringDefault(fontName, @"NSUserFixedPitchFont"); setFloatDefault(fontSize, @"NSUserFixedPitchFontSize"); - } - else if ([fontKey isEqualToString:@"NSFont"]) { // System + } else if ([fontKey isEqualToString:@"NSFont"]) { // System // NSFont, NSFontSize=12 setStringDefault(fontName, @"NSFont"); setFloatDefault(fontSize, @"NSFontSize"); @@ -428,11 +423,13 @@ - (void)changeFont:(id)sender setFloatDefault(fontSize - 3.0, @"NSMiniFontSize"); setFloatDefault(fontSize - 2.0, @"NSSmallFontSize"); // WM - [self setWMFont:[NSFont fontWithName:fontName size:fontSize - 3.0] key:@"IconTitleFont"]; [self setWMFont:font key:@"MenuTextFont"]; + [self setWMFont:[NSFont fontWithName:fontName size:fontSize - 3.0] key:@"IconTitleFont"]; [self setWMFont:[NSFont fontWithName:fontName size:fontSize * 2.0] key:@"LargeDisplayFont"]; - } - else if ([fontKey isEqualToString:@"NSBoldFont"]) { // Bold System + [[NSDistributedNotificationCenter defaultCenter] + postNotificationName:@"WMPreferencesDidChangeNotification" + object:@"GSWorkspaceNotification"]; + } else if ([fontKey isEqualToString:@"NSBoldFont"]) { // Bold System // NSBoldFont, NSBoldFontSize=12 setStringDefault(fontName, @"NSBoldFont"); setFloatDefault(fontSize, @"NSBoldFontSize"); @@ -447,8 +444,10 @@ - (void)changeFont:(id)sender // WM [self setWMFont:font key:@"MenuTitleFont"]; [self setWMFont:font key:@"WindowTitleFont"]; - } - else if ([fontKey isEqualToString:@"NSToolTipsFont"]) { // Tool Tips + [[NSDistributedNotificationCenter defaultCenter] + postNotificationName:@"WMPreferencesDidChangeNotification" + object:@"GSWorkspaceNotification"]; + } else if ([fontKey isEqualToString:@"NSToolTipsFont"]) { // Tool Tips // NSToolTipsFont, NSToolTipsFontSize=11 setStringDefault(fontName, @"NSToolTipsFont"); setFloatDefault(fontSize, @"NSToolTipsFontSize"); @@ -457,8 +456,8 @@ - (void)changeFont:(id)sender [defaults synchronize]; [self updateUI]; [[NSDistributedNotificationCenter defaultCenter] - postNotificationName:@"NXTSystemFontPreferencesDidChangeNotification" - object:@"Preferences"]; + postNotificationName:@"NXTSystemFontPreferencesDidChangeNotification" + object:@"Preferences"]; } @end // Font diff --git a/Applications/Workspace/WM/WM.h b/Applications/Workspace/WM/WM.h index 71dddeff4..8cdb78396 100644 --- a/Applications/Workspace/WM/WM.h +++ b/Applications/Workspace/WM/WM.h @@ -378,7 +378,8 @@ extern CFStringRef WMDidCreateDesktopNotification; extern CFStringRef WMDidDestroyDesktopNotification; extern CFStringRef WMDidChangeDesktopNotification; extern CFStringRef WMDidChangeDesktopNameNotification; -/* Appearance */ +/* Appearance and settings - WM.plist */ +extern CFStringRef WMPreferencesDidChangeNotification; // for notification with changes made outside of WM extern CFStringRef WMDidChangeWindowAppearanceSettings; extern CFStringRef WMDidChangeIconAppearanceSettings; extern CFStringRef WMDidChangeIconTileSettings; diff --git a/Applications/Workspace/WM/defaults.c b/Applications/Workspace/WM/defaults.c index f89e04baf..b53eae8b4 100644 --- a/Applications/Workspace/WM/defaults.c +++ b/Applications/Workspace/WM/defaults.c @@ -736,15 +736,14 @@ static void _updateDomain(WDDomain *domain, Bool shouldNotify) } #ifdef HAVE_INOTIFY - wDefaultsShouldTrackChanges(domain, false); + if (domain->inotify_watch >= 0) { + wDefaultsShouldTrackChanges(domain, false); + } #endif WMLogWarning("Updating domain %@...", domain->name); /* User dictionary */ dict = (CFMutableDictionaryRef)WMUserDefaultsRead(domain->name, false); - if (CFStringCompare(domain->name, CFSTR("WM"), 0) == 0) { - WMLogWarning("Updating domain %@ with dictionary: %@", domain->name, dict); - } if (dict) { if (CFGetTypeID(dict) == CFDictionaryGetTypeID()) { if ((scr = wDefaultScreen()) && CFStringCompare(domain->name, CFSTR("WM"), 0) == 0) { @@ -769,7 +768,9 @@ static void _updateDomain(WDDomain *domain, Bool shouldNotify) domain->timestamp = WMUserDefaultsFileModificationTime(domain->name, 0); #ifdef HAVE_INOTIFY - wDefaultsShouldTrackChanges(domain, true); + if (domain->shouldTrackChanges) { + wDefaultsShouldTrackChanges(domain, true); + } #endif } @@ -853,35 +854,46 @@ static void _processWatchEvents(CFFileDescriptorRef fdref, CFOptionFlags callBac CFFileDescriptorEnableCallBacks(fdref, kCFFileDescriptorReadCallBack); } +static Bool _initializeInotify() +{ + w_global.inotify.fd_event_queue = inotify_init(); + if (w_global.inotify.fd_event_queue < 0) { + WMLogWarning("** inotify ** could not initialise an inotify instance." + " Changes to the defaults database will require a restart to take effect."); + return False; + } else { // Add to runloop + CFFileDescriptorRef ifd = NULL; + CFRunLoopSourceRef ifd_source = NULL; + + ifd = CFFileDescriptorCreate(kCFAllocatorDefault, w_global.inotify.fd_event_queue, true, + _processWatchEvents, NULL); + CFFileDescriptorEnableCallBacks(ifd, kCFFileDescriptorReadCallBack); + + ifd_source = CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, ifd, 0); + CFRunLoopAddSource(wm_runloop, ifd_source, kCFRunLoopDefaultMode); + CFRelease(ifd_source); + CFRelease(ifd); + } + + return True; +} + void wDefaultsShouldTrackChanges(WDDomain *domain, Bool shouldTrack) { CFStringRef domainPath = NULL; - const char *watchPath = NULL; + const char *watchPath = NULL; - if (!domain) + if (!domain) { return; + } - // Initialize inotify - if (w_global.inotify.fd_event_queue < 0) { - w_global.inotify.fd_event_queue = inotify_init(); - if (w_global.inotify.fd_event_queue < 0) { - WMLogWarning(_("** inotify ** could not initialise an inotify instance." - " Changes to the defaults database will require a restart to take effect.")); - return; - } - else { // Add to runloop - CFFileDescriptorRef ifd = NULL; - CFRunLoopSourceRef ifd_source = NULL; - - ifd = CFFileDescriptorCreate(kCFAllocatorDefault, w_global.inotify.fd_event_queue, true, - _processWatchEvents, NULL); - CFFileDescriptorEnableCallBacks(ifd, kCFFileDescriptorReadCallBack); + if (!wm_runloop) { + return; + } - ifd_source = CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, ifd, 0); - CFRunLoopAddSource(wm_runloop, ifd_source, kCFRunLoopDefaultMode); - CFRelease(ifd_source); - CFRelease(ifd); - } + // Initialize inotify if needed + if ((w_global.inotify.fd_event_queue < 0) && (_initializeInotify() == False)) { + return; } // Create watcher @@ -895,33 +907,40 @@ void wDefaultsShouldTrackChanges(WDDomain *domain, Bool shouldTrack) domain->inotify_watch = inotify_add_watch(w_global.inotify.fd_event_queue, watchPath, mask); if (domain->inotify_watch < 0) { - WMLogWarning(_("** inotify ** could not add an inotify watch on path %s (error: %i %s)." - " Changes to the defaults database will require a restart to take effect."), + WMLogWarning("** inotify ** could not add an inotify watch on path %s (error: %i %s)." + " Changes to the defaults database will require a restart to take effect.", watchPath, errno, strerror(errno)); } CFRelease(domainPath); - } - else if (domain->inotify_watch >= 0) { + } else if (domain->inotify_watch >= 0) { WMLogError("inotify: will remove watch for %@.", domain->name); - - if (domain->inotify_watch >= 0) { - inotify_rm_watch(w_global.inotify.fd_event_queue, domain->inotify_watch); - } + inotify_rm_watch(w_global.inotify.fd_event_queue, domain->inotify_watch); domain->inotify_watch = -1; } + // else shouldTrack == false but domain is not tracked for changes - do nothing. } #endif /* HAVE_INOTIFY */ +static void _settingsObserver(CFNotificationCenterRef center, + void *observer, // NULL + CFNotificationName name, + const void *object, // object - ignored + CFDictionaryRef userInfo) +{ + wDefaultsUpdateDomainsIfNeeded(NULL); +} + // Called from startup.c +static Bool isOptionListsIntialized = false; +static Bool isObserverSet = false; WDDomain *wDefaultsInitDomain(const char *domain_name, Bool shouldTrackChanges) { WDDomain *domain; - static int inited = 0; CFMutableDictionaryRef dict; - if (!inited) { - inited = 1; + if (isOptionListsIntialized == false) { + isOptionListsIntialized = true; _initializeOptionLists(); } @@ -931,6 +950,7 @@ WDDomain *wDefaultsInitDomain(const char *domain_name, Bool shouldTrackChanges) domain = wmalloc(sizeof(WDDomain)); domain->name = CFStringCreateWithCString(kCFAllocatorDefault, domain_name, kCFStringEncodingUTF8); domain->inotify_watch = -1; + domain->shouldTrackChanges = shouldTrackChanges; // Initializing domain->dictionary dict = (CFMutableDictionaryRef)WMUserDefaultsRead(domain->name, true); @@ -945,9 +965,8 @@ WDDomain *wDefaultsInitDomain(const char *domain_name, Bool shouldTrackChanges) CFRelease(dict); } else { WMLogError("creating empty domain: %@", domain->name); - domain->dictionary = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); + domain->dictionary = CFDictionaryCreateMutable( + kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } if (domain->dictionary && WMUserDefaultsWrite(domain->dictionary, domain->name)) { @@ -959,9 +978,14 @@ WDDomain *wDefaultsInitDomain(const char *domain_name, Bool shouldTrackChanges) domain->path = CFURLCreateCopyAppendingPathExtension(NULL, osURL, CFSTR("plist")); CFRelease(osURL); - if (wm_runloop) { - WMLogInfo("start tracking changes for domain: %@", domain->name); - wDefaultsShouldTrackChanges(domain, shouldTrackChanges); + wDefaultsShouldTrackChanges(domain, shouldTrackChanges); + + // first domain without tracking changes (inotify) + if ((shouldTrackChanges == false) && (isObserverSet == false)) { + WMLogError("Setting up `WMSettingsDidChangeNotification` observer..."); + CFNotificationCenterAddObserver(CFNotificationCenterGetLocalCenter(), NULL, _settingsObserver, + WMPreferencesDidChangeNotification, NULL, + CFNotificationSuspensionBehaviorDeliverImmediately); } } diff --git a/Applications/Workspace/WM/defaults.h b/Applications/Workspace/WM/defaults.h index d0fa5af90..55dfd1dcf 100644 --- a/Applications/Workspace/WM/defaults.h +++ b/Applications/Workspace/WM/defaults.h @@ -33,6 +33,7 @@ typedef struct WDDomain { CFMutableDictionaryRef dictionary; CFURLRef path; CFAbsoluteTime timestamp; + Bool shouldTrackChanges; #ifdef HAVE_INOTIFY int inotify_watch; #endif diff --git a/Applications/Workspace/WM/event.c b/Applications/Workspace/WM/event.c index 993dd23bc..c15b9e300 100644 --- a/Applications/Workspace/WM/event.c +++ b/Applications/Workspace/WM/event.c @@ -328,7 +328,6 @@ void WMRunLoop_V0() #ifdef HAVE_INOTIFY /* Track some defaults files for changes */ w_global.inotify.fd_event_queue = -1; - wDefaultsShouldTrackChanges(w_global.domain.wm_preferences, true); wDefaultsShouldTrackChanges(w_global.domain.window_attrs, true); #else /* Setup defaults files polling */ diff --git a/Applications/Workspace/WM/screen.c b/Applications/Workspace/WM/screen.c index 1b8d8572d..267250b80 100644 --- a/Applications/Workspace/WM/screen.c +++ b/Applications/Workspace/WM/screen.c @@ -801,7 +801,6 @@ WScreen *wScreenInit(int screen_number) /* read defaults for this screen */ wDefaultsReadPreferences(scr, w_global.domain.wm_preferences->dictionary, True); - fprintf(stderr, "Menu item font is: %s\n", scr->menu_item_font->name); { XColor xcol; diff --git a/Applications/Workspace/WM/startup.c b/Applications/Workspace/WM/startup.c index b0cc32a73..6695cb236 100644 --- a/Applications/Workspace/WM/startup.c +++ b/Applications/Workspace/WM/startup.c @@ -107,6 +107,9 @@ CFStringRef WMDidDestroyDesktopNotification = CFSTR("WMDidDestroyDesktopNotifica CFStringRef WMDidChangeDesktopNotification = CFSTR("WMDidChangeDesktopNotification"); CFStringRef WMDidChangeDesktopNameNotification = CFSTR("WMDidChangeDesktopNameNotification"); +// WM.plist +CFStringRef WMPreferencesDidChangeNotification = CFSTR("WMPreferencesDidChangeNotification"); + CFStringRef WMDidChangeWindowAppearanceSettings = CFSTR("WMDidChangeWindowAppearanceSettings"); CFStringRef WMDidChangeIconAppearanceSettings = CFSTR("WMDidChangeIconAppearanceSettings"); CFStringRef WMDidChangeIconTileSettings = CFSTR("WMDidChangeIconTileSettings"); @@ -115,6 +118,7 @@ CFStringRef WMDidChangeMenuTitleAppearanceSettings = CFSTR("WMDidChangeMenuTitleAppearanceSettings"); CFStringRef WMDidChangeKeyboardLayoutNotification = CFSTR("WMDidChangeKeyboardLayoutNotification"); +// WMState.plist CFStringRef WMDidChangeDockContentNotification = CFSTR("WMDidChangeDockContentNotification"); /* GNUstep applications notifications */ @@ -655,9 +659,9 @@ void wStartUp(Bool defaultScreenOnly) */ // Read defaults from WM.plist file. This file may not exist - use hardcoded defults (defaults.c). // Defaults are propagated into wPreferences, WScreen. - w_global.domain.wm_preferences = wDefaultsInitDomain("WM", true); + w_global.domain.wm_preferences = wDefaultsInitDomain("WM", false); if (!w_global.domain.wm_preferences->dictionary) { - WMLogWarning(_("could not read domain \"%s\" from defaults database"), "WMState"); + WMLogWarning("could not read domain \"WM\" from defaults database"); } // Process defaults that don't change until a restart and are screen independent. @@ -671,12 +675,12 @@ void wStartUp(Bool defaultScreenOnly) w_global.domain.wm_state = wDefaultsInitDomain("WMState", true); if (!w_global.domain.wm_state->dictionary) { - WMLogWarning(_("could not read domain \"%s\" from defaults database"), "WMState"); + WMLogWarning("could not read domain \"WMState\" from defaults database"); } /* check sanity of some values */ if (wPreferences.icon_size < 64) { - WMLogWarning(_("Icon size is configured to %i, but it's too small. Using 64 instead"), + WMLogWarning("Icon size is configured to %i, but it's too small. Using 64 instead", wPreferences.icon_size); wPreferences.icon_size = 64; } @@ -684,7 +688,7 @@ void wStartUp(Bool defaultScreenOnly) /* init other domains */ w_global.domain.window_attrs = wDefaultsInitDomain("WMWindowAttributes", true); if (!w_global.domain.window_attrs->dictionary) { - WMLogWarning(_("could not read domain \"%s\" from defaults database"), "WMWindowAttributes"); + WMLogWarning("could not read domain \"WMWindowAttributes\" from defaults database"); } wSetErrorHandler(); diff --git a/Applications/Workspace/WMNotificationCenter.m b/Applications/Workspace/WMNotificationCenter.m index bbd43f1f5..c92ac5f22 100644 --- a/Applications/Workspace/WMNotificationCenter.m +++ b/Applications/Workspace/WMNotificationCenter.m @@ -151,7 +151,7 @@ - (void)_handleRemoteNotification:(NSNotification *)aNotification convertNStoCFString(objectName)); } - if ([name hasPrefix:@"WMShould"]) { + if ([name hasPrefix:@"WM"]) { [self _postCFNotification:name userInfo:[aNotification userInfo]]; } else { // Examples: From 1d5eaf4c6ddcf1a4c8ee3ecf591f9964cff5b24f Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Fri, 27 Oct 2023 15:52:33 +0300 Subject: [PATCH 48/67] DosktopKit: create NXTWorkspace to hold notification names complementary to Worksapce's CFString. This notifications could be send by GNUstep apps to NSGlobalNotificationCenter and will be precessed by Workspace and WM. Preferences: use previous change to inform Workspace WM about WM.plist font changes. --- Applications/Preferences/Modules/Font/Font.m | 6 ++- Applications/Workspace/WM/WM.h | 15 ++++--- Applications/Workspace/WM/application.c | 2 +- Applications/Workspace/WM/defaults.c | 2 +- Applications/Workspace/WM/startup.c | 9 ++-- Frameworks/DesktopKit/GNUmakefile | 2 + Frameworks/DesktopKit/NXTWorkspace.h | 46 ++++++++++++++++++++ Frameworks/DesktopKit/NXTWorkspace.m | 30 +++++++++++++ 8 files changed, 97 insertions(+), 15 deletions(-) create mode 100644 Frameworks/DesktopKit/NXTWorkspace.h create mode 100644 Frameworks/DesktopKit/NXTWorkspace.m diff --git a/Applications/Preferences/Modules/Font/Font.m b/Applications/Preferences/Modules/Font/Font.m index bf1820818..aed899e4c 100644 --- a/Applications/Preferences/Modules/Font/Font.m +++ b/Applications/Preferences/Modules/Font/Font.m @@ -40,6 +40,8 @@ #import #import +#import + #import "Font.h" @interface Font (Private) @@ -427,7 +429,7 @@ - (void)changeFont:(id)sender [self setWMFont:[NSFont fontWithName:fontName size:fontSize - 3.0] key:@"IconTitleFont"]; [self setWMFont:[NSFont fontWithName:fontName size:fontSize * 2.0] key:@"LargeDisplayFont"]; [[NSDistributedNotificationCenter defaultCenter] - postNotificationName:@"WMPreferencesDidChangeNotification" + postNotificationName:WMDidChangeAppearanceSettingsNotification object:@"GSWorkspaceNotification"]; } else if ([fontKey isEqualToString:@"NSBoldFont"]) { // Bold System // NSBoldFont, NSBoldFontSize=12 @@ -445,7 +447,7 @@ - (void)changeFont:(id)sender [self setWMFont:font key:@"MenuTitleFont"]; [self setWMFont:font key:@"WindowTitleFont"]; [[NSDistributedNotificationCenter defaultCenter] - postNotificationName:@"WMPreferencesDidChangeNotification" + postNotificationName:WMDidChangeAppearanceSettingsNotification object:@"GSWorkspaceNotification"]; } else if ([fontKey isEqualToString:@"NSToolTipsFont"]) { // Tool Tips // NSToolTipsFont, NSToolTipsFontSize=11 diff --git a/Applications/Workspace/WM/WM.h b/Applications/Workspace/WM/WM.h index 8cdb78396..bc9ccb266 100644 --- a/Applications/Workspace/WM/WM.h +++ b/Applications/Workspace/WM/WM.h @@ -379,7 +379,6 @@ extern CFStringRef WMDidDestroyDesktopNotification; extern CFStringRef WMDidChangeDesktopNotification; extern CFStringRef WMDidChangeDesktopNameNotification; /* Appearance and settings - WM.plist */ -extern CFStringRef WMPreferencesDidChangeNotification; // for notification with changes made outside of WM extern CFStringRef WMDidChangeWindowAppearanceSettings; extern CFStringRef WMDidChangeIconAppearanceSettings; extern CFStringRef WMDidChangeIconTileSettings; @@ -388,18 +387,22 @@ extern CFStringRef WMDidChangeMenuTitleAppearanceSettings; /* Other */ // userInfo = { "XkbGroup" = CFNumber } extern CFStringRef WMDidChangeKeyboardLayoutNotification; -extern CFStringRef WMDidChangeDockContentNotification; /* Notifications to communicate with applications. Manadatory prefixes in notification names are: - WMShould for notification from application to perform some action - WMDid to notify application about action completion + Every WMDid should complement WMShould notification. - Every WMDid should complement WMDid notification. - - All notifications must contain in userInfo: + All WMShould* and WMDid* notifications must contain in userInfo: "WindowID" = CFNumber; - "ApplicationName" = CFString; */ + "ApplicationName" = CFString; + Objective C definitions located in DesktopKit/NXTWorkspace.[hm]. +*/ +// WM.plist +extern CFStringRef WMDidChangeAppearanceSettingsNotification; +// WMState.plist +extern CFStringRef WMDidChangeDockContentNotification; // Hide All extern CFStringRef WMShouldHideOthersNotification; extern CFStringRef WMDidHideOthersNotification; diff --git a/Applications/Workspace/WM/application.c b/Applications/Workspace/WM/application.c index f36013962..d558b98bc 100644 --- a/Applications/Workspace/WM/application.c +++ b/Applications/Workspace/WM/application.c @@ -359,7 +359,7 @@ WApplication *wApplicationCreate(WWindow *wwin) // Notify Workspace's ProcessManager CFNotificationCenterPostNotification(scr->notificationCenter, - WMDidCreateApplicationNotification, wapp, NULL, TRUE); + WMDidCreateApplicationNotification, wapp, NULL, true); } return wapp; diff --git a/Applications/Workspace/WM/defaults.c b/Applications/Workspace/WM/defaults.c index b53eae8b4..ddfa9609d 100644 --- a/Applications/Workspace/WM/defaults.c +++ b/Applications/Workspace/WM/defaults.c @@ -984,7 +984,7 @@ WDDomain *wDefaultsInitDomain(const char *domain_name, Bool shouldTrackChanges) if ((shouldTrackChanges == false) && (isObserverSet == false)) { WMLogError("Setting up `WMSettingsDidChangeNotification` observer..."); CFNotificationCenterAddObserver(CFNotificationCenterGetLocalCenter(), NULL, _settingsObserver, - WMPreferencesDidChangeNotification, NULL, + WMDidChangeAppearanceSettingsNotification, NULL, CFNotificationSuspensionBehaviorDeliverImmediately); } } diff --git a/Applications/Workspace/WM/startup.c b/Applications/Workspace/WM/startup.c index 6695cb236..f9b144a31 100644 --- a/Applications/Workspace/WM/startup.c +++ b/Applications/Workspace/WM/startup.c @@ -107,9 +107,6 @@ CFStringRef WMDidDestroyDesktopNotification = CFSTR("WMDidDestroyDesktopNotifica CFStringRef WMDidChangeDesktopNotification = CFSTR("WMDidChangeDesktopNotification"); CFStringRef WMDidChangeDesktopNameNotification = CFSTR("WMDidChangeDesktopNameNotification"); -// WM.plist -CFStringRef WMPreferencesDidChangeNotification = CFSTR("WMPreferencesDidChangeNotification"); - CFStringRef WMDidChangeWindowAppearanceSettings = CFSTR("WMDidChangeWindowAppearanceSettings"); CFStringRef WMDidChangeIconAppearanceSettings = CFSTR("WMDidChangeIconAppearanceSettings"); CFStringRef WMDidChangeIconTileSettings = CFSTR("WMDidChangeIconTileSettings"); @@ -118,10 +115,12 @@ CFStringRef WMDidChangeMenuTitleAppearanceSettings = CFSTR("WMDidChangeMenuTitleAppearanceSettings"); CFStringRef WMDidChangeKeyboardLayoutNotification = CFSTR("WMDidChangeKeyboardLayoutNotification"); + +/* GNUstep applications notifications. Public ObjC part resides in DesktopKit/NXTWorkspace.h */ +// WM.plist +CFStringRef WMDidChangeAppearanceSettingsNotification = CFSTR("WMDidChangeAppearanceSettingsNotification"); // WMState.plist CFStringRef WMDidChangeDockContentNotification = CFSTR("WMDidChangeDockContentNotification"); - -/* GNUstep applications notifications */ // Hide Others CFStringRef WMShouldHideOthersNotification = CFSTR("WMShouldHideOthersNotification"); CFStringRef WMDidHideOthersNotification = CFSTR("WMDidHideOthersNotification"); diff --git a/Frameworks/DesktopKit/GNUmakefile b/Frameworks/DesktopKit/GNUmakefile index bc1b08d72..58bb7f2b0 100644 --- a/Frameworks/DesktopKit/GNUmakefile +++ b/Frameworks/DesktopKit/GNUmakefile @@ -34,6 +34,7 @@ $(FRAMEWORK_NAME)_OBJC_FILES = \ NXTOpenPanel.m \ NXTHelpPanel.m \ NXTListView.m \ + NXTWorkspace.m \ \ Utilities.m @@ -60,6 +61,7 @@ $(FRAMEWORK_NAME)_HEADER_FILES = \ NXTOpenPanel.h \ NXTHelpPanel.h \ NXTListView.h \ + NXTWorkspace.h \ \ Utilities.h diff --git a/Frameworks/DesktopKit/NXTWorkspace.h b/Frameworks/DesktopKit/NXTWorkspace.h new file mode 100644 index 000000000..1ca3c72b1 --- /dev/null +++ b/Frameworks/DesktopKit/NXTWorkspace.h @@ -0,0 +1,46 @@ +#import + +/* Notifications to communicate with applications. Manadatory prefixes in + notification names are: + - WMShould for notification from application to perform some action + - WMDid to notify application about action completion + Every WMDid should complement WMShould notification. + + All notifications object must be set to @"GSWorkspaceNotification". + Otherwise Workspace Manager will ignore this notification. + All notifications must contain in userInfo: + "WindowID" = CFNumber; + "ApplicationName" = CFString; +*/ +// WM.plist +extern NSString* WMDidChangeAppearanceSettingsNotification; +// WMState.plist +extern NSString* WMDidChangeDockContentNotification; +// Hide All +extern NSString* WMShouldHideOthersNotification; +extern NSString* WMDidHideOthersNotification; +// Quit or Force Quit +extern NSString* WMShouldTerminateApplicationNotification; +extern NSString* WMDidTerminateApplicationNotification; +// Zoom Window +/* additional userInfo element: + "ZoomType" = "Vertical" | "Horizontal" | "Maximize"; */ +extern NSString* WMShouldZoomWindowNotification; +extern NSString* WMDidZoomWindowNotification; +// Tile Window +/* additional userInfo element: + "TileDirection" = "Left" | "Right" | "Top" | "Bottom"; */ +extern NSString* WMShouldTileWindowNotification; +extern NSString* WMDidTileWindowNotification; +// Shade Window +extern NSString* WMShouldShadeWindowNotification; +extern NSString* WMDidShadeWindowNotification; +// Arrange in Front +extern NSString* WMShouldArrangeWindowsNotification; +extern NSString* WMDidArrangeWindowsNotification; +// Miniaturize Window +extern NSString* WMShouldMinmizeWindowNotification; +extern NSString* WMDidMinmizeWindowNotification; +// Close Window +extern NSString* WMShouldCloseWindowNotification; +extern NSString* WMDidCloseWindowNotification; \ No newline at end of file diff --git a/Frameworks/DesktopKit/NXTWorkspace.m b/Frameworks/DesktopKit/NXTWorkspace.m new file mode 100644 index 000000000..f05a73b42 --- /dev/null +++ b/Frameworks/DesktopKit/NXTWorkspace.m @@ -0,0 +1,30 @@ +#import "NXTWorkspace.h" + +// WM.plist +NSString* WMDidChangeAppearanceSettingsNotification = @"WMDidChangeAppearanceSettingsNotification"; +// WMState.plist +NSString* WMDidChangeDockContentNotification = @"WMDidChangeDockContentNotification"; +// Hide Others +NSString* WMShouldHideOthersNotification = @"WMShouldHideOthersNotification"; +NSString* WMDidHideOthersNotification = @"WMDidHideOthersNotification"; +// Quit or Force Quit +NSString* WMShouldTerminateApplicationNotification = @"WMShouldTerminateApplicationNotification"; +NSString * WMDidTerminateApplicationNotification = @"WMDidTerminateApplicationNotification"; +// Windows -> Zoom Window +NSString* WMShouldZoomWindowNotification = @"WMShouldZoomWindowNotification"; +NSString* WMDidZoomWindowNotification = @"WMDidZoomWindowNotification"; +// Windows -> Tile Window -> Left | Right | Top | Bottom +NSString* WMShouldTileWindowNotification = @"WMShouldTileWindowNotification"; +NSString* WMDidTileWindowNotification = @"WMDidTileWindowNotification"; +// Windows -> Shade Window +NSString* WMShouldShadeWindowNotification = @"WMShouldShadeWindowNotification"; +NSString* WMDidShadeWindowNotification = @"WMDidShadeWindowNotification"; +// Windows -> Arrange in Front +NSString* WMShouldArrangeWindowsNotification = @"WMShouldArrangeWindowsNotification"; +NSString* WMDidArrangeWindowsNotification = @"WMDidArrangeWindowsNotification"; +// Windows -> Miniaturize Window +NSString * WMShouldMinmizeWindowNotification = @"WMShouldMinmizeWindowNotification"; +NSString* WMDidMinmizeWindowNotification = @"WMDidMinmizeWindowNotification"; +// Windows -> Close Window +NSString* WMShouldCloseWindowNotification = @"WMShouldCloseWindowNotification"; +NSString* WMDidCloseWindowNotification = @"WMDidCloseWindowNotification"; From 9cc787929ae1ea288fa5983a135f1c1e662ae379 Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Fri, 27 Oct 2023 16:13:00 +0300 Subject: [PATCH 49/67] add copyright to a new files. --- Frameworks/DesktopKit/NXTWorkspace.h | 21 +++++++++++++++++++++ Frameworks/DesktopKit/NXTWorkspace.m | 23 ++++++++++++++++++++++- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/Frameworks/DesktopKit/NXTWorkspace.h b/Frameworks/DesktopKit/NXTWorkspace.h index 1ca3c72b1..5456c3da2 100644 --- a/Frameworks/DesktopKit/NXTWorkspace.h +++ b/Frameworks/DesktopKit/NXTWorkspace.h @@ -1,3 +1,24 @@ +/* -*- mode: objc -*- */ +// +// Project: NEXTSPACE - DesktopKit framework +// +// Copyright (C) 2014-present Sergii Stoian +// +// This application is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This application is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this library; if not, write to the Free +// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. +// + #import /* Notifications to communicate with applications. Manadatory prefixes in diff --git a/Frameworks/DesktopKit/NXTWorkspace.m b/Frameworks/DesktopKit/NXTWorkspace.m index f05a73b42..bbb10cadb 100644 --- a/Frameworks/DesktopKit/NXTWorkspace.m +++ b/Frameworks/DesktopKit/NXTWorkspace.m @@ -1,3 +1,24 @@ +/* -*- mode: objc -*- */ +// +// Project: NEXTSPACE - DesktopKit framework +// +// Copyright (C) 2014-present Sergii Stoian +// +// This application is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This application is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this library; if not, write to the Free +// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. +// + #import "NXTWorkspace.h" // WM.plist @@ -9,7 +30,7 @@ NSString* WMDidHideOthersNotification = @"WMDidHideOthersNotification"; // Quit or Force Quit NSString* WMShouldTerminateApplicationNotification = @"WMShouldTerminateApplicationNotification"; -NSString * WMDidTerminateApplicationNotification = @"WMDidTerminateApplicationNotification"; +NSString* WMDidTerminateApplicationNotification = @"WMDidTerminateApplicationNotification"; // Windows -> Zoom Window NSString* WMShouldZoomWindowNotification = @"WMShouldZoomWindowNotification"; NSString* WMDidZoomWindowNotification = @"WMDidZoomWindowNotification"; From 4791c5ee7f19cc6c16e4f5066cad3c641dea14b9 Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Fri, 27 Oct 2023 18:03:05 +0300 Subject: [PATCH 50/67] initial implementation of "Hide Others" was added. --- .clang-format | 2 ++ Applications/Workspace/Controller.m | 14 ++++++++++---- .../WorkspaceManager.gorm/data.classes | 3 ++- .../WorkspaceManager.gorm/data.info | Bin 184 -> 184 bytes .../WorkspaceManager.gorm/objects.gorm | Bin 17642 -> 17897 bytes .../Workspace/Processes/ProcessManager.m | 3 ++- 6 files changed, 16 insertions(+), 6 deletions(-) diff --git a/.clang-format b/.clang-format index 4a284be50..ad5325b55 100644 --- a/.clang-format +++ b/.clang-format @@ -22,3 +22,5 @@ AllowAllArgumentsOnNextLine: false PointerAlignment: Right ColumnLimit: 100 SortIncludes: Never +PointerAlignment: Right +AlignConsecutiveBitFields: AcrossEmptyLinesAndComments diff --git a/Applications/Workspace/Controller.m b/Applications/Workspace/Controller.m index 98c0398f7..36e530c15 100644 --- a/Applications/Workspace/Controller.m +++ b/Applications/Workspace/Controller.m @@ -29,7 +29,8 @@ #include #import -#import +#import + #import #import #import @@ -59,9 +60,6 @@ #import #import -#import -#import - static NSString *WorkspaceVersion = @"0.8"; //============================================================================ @@ -854,6 +852,14 @@ - (void)openFileViewerService:(NSPasteboard *)pboard } } +- (void)hideOtherApplications:(id)sender +{ + NSLog(@"hideOtherApplications"); + [[NSDistributedNotificationCenter defaultCenter] + postNotificationName:CF_NOTIFICATION(WMShouldHideOthersNotification) + object:@"GSWorkspaceNotification"]; +} + //============================================================================ // Access to Workspace data via NSApp //============================================================================ diff --git a/Applications/Workspace/English.lproj/WorkspaceManager.gorm/data.classes b/Applications/Workspace/English.lproj/WorkspaceManager.gorm/data.classes index 2f128f15c..18cef8c95 100644 --- a/Applications/Workspace/English.lproj/WorkspaceManager.gorm/data.classes +++ b/Applications/Workspace/English.lproj/WorkspaceManager.gorm/data.classes @@ -24,7 +24,8 @@ "setDockCollapse:", "setIconYardVisibility:", "showHelpPanel:", - "hide:" + "hide:", + "hideOtherApplications:" ); Outlets = ( deviceManager, diff --git a/Applications/Workspace/English.lproj/WorkspaceManager.gorm/data.info b/Applications/Workspace/English.lproj/WorkspaceManager.gorm/data.info index c2d6894a68792c008546fbacbbbe83769b7db8bd..a97a2a906f0a4e3651d10306d9c0dff5738135af 100644 GIT binary patch delta 12 TcmdnNxPx&*Dibr~#PmP_8YBa^ delta 12 TcmdnNxPx&*Dif2`#PmP_8iNDR diff --git a/Applications/Workspace/English.lproj/WorkspaceManager.gorm/objects.gorm b/Applications/Workspace/English.lproj/WorkspaceManager.gorm/objects.gorm index be27c85cde7813026c772fa3328f3ebbbafc5396..263c8235f9eee3e2e1631b224240127383c29158 100644 GIT binary patch delta 4950 zcmZu#cX*Z68PEHf``rtd5D-HWax-og+=OxNOv1_l+2bHev4|K+KoAIqAksc9NTq^E z0gs4O45A{4RKL`{7;ddX+!JTrqqw*9_rB*TkA2$ze(yZLcbs#-mhpscrvL_Kv5+;YM>|Zk|7;BHm=R$3(Mx2RPVkS2vkxUdSJdN4%M8uX(y} zjtjV6{Y}*Is)*O1ZZ_e{kT2nFRkt8ApF9(dX1mo9FGF>hw{rTV$5URTIhvjCkH;e3 zCUvXX6b-r2i07)?}c|T2^3~ukM3)A>D5%H=p(iqeR4;q4u+jF9G6%&4Ju}e*%mfDlX_O#pY%qm=d4m;hR>V4Pzk*tG;v;U^`Znv5v-V+9BRJnRzP6e5*>H|v#xJi8| zI1V^`$g72uVvjC~>WKOoxA+&i)yK@7@VFB+r7`CKZ%DZ&Vy5P3I2{Iu z4Zb9bnQ2xQ7j&yZ0V}+n-u0T&xxaoK9?|6EuDfyXa!oErnD$~n`T15ormZqz22HKg>4dS z$7|{#LJACVcux^((C}%RPUI`(DsP3RUYJx7og|F0in*Gygy!~AKlPTF7z%6Blr2OQ zsBY4fBShez(3ERls4hZ7`j}){nDQ)Nkl&#xggUdOlI5E6nQ+$xdQ#BQMN^?USauo} zi96rWb(+FFN-l4TreYqsTjkBrRKi2^$7{U#no5NduU;=rWh|7XQ0*E`<@U99kH6Ng zGimC?=0!_AaO=z4=0_)rH1)ITV&3VRB61UE^>wMj)@u7xDdnM5knL|7qSm>Z27qA! z4dhA!D$+>>ng)qI4%VwQDIP3W(4r~IlRqKhZ82~3D+t6f!FEk?IR>ldRcT5HE70$$ zDG5W!{L;^*lqBTqdzGdto~YkJ?fQcsug_#RH3gER=jbTLOly+VTGR>n3Es;Fy#@f^(8^P(bQEI1ZvPs z6nwIbsoI;RX_W12+*_?_G}K`lBbm;u^wU_&0)(-OCN%mjT7t;atlORB@3OSazrY z_jI8MybOaiEfSI|luIp8hx}+Io}0yTEZ;S3<#}=}_+ad`iq@Vk~ek(rXHq^lIV3L+9WaZv#;qgO9Q;Y$zTmi=yFR2G||S*5c2&X zhI?{_1SUZY`@Thl8VnoH#g!tYFl;n?tIW4H<(o9!odD}UUhL$^dT)4EUMkMa>MixxG{Zfj}fFY&ZaD(|G+jheiU%uc!tB5()e zOD+C8;~Oo$)fChe`B~6(n>lZ2@tE7$+71Uq-NAS^MBqCaZ?pI=#(ONjn{k!Rc27qS zi#6TL$-?)s@jB>`;C{x_Ap-AX$LX5(n=fjLR~)dvcIn4|?b4muOWUvz2RYh)Uh`@&#Z?(9S@fwStX1u}TXBanH z{4C>3EPjshE{mUMe3d=?1wNdyrWb87-OU9<^GaW0pY<@|+?N?&2@&`e_6J5KubO>B zN^)LfW41LOVIwe%ubc0O^v!vLjlZ$RH`xdb<6EYBXgKF>HlAW>yu(Ju8eiM!LFv0} zY=aJGzQ_0q>-au9GS>6~JC6L2jjN!8<425FKm`7n@m`BR>B#gBTlgufx7b{taW2ND zWmrXJ7#MM%v%}g>3Il(^xXC(y$b4{hEz6(82K=#+x7lf6I8c#osZ$#^Uce z0b@-+aDrJsvT+G?2>OZf2#CNxGhS!$FN~*Ie2nqAf}J$Rb0o1tsBWj+Ovm9fur2$w zbAp*NJSW3RXASlQ8lO3TcsS*M%L&FI?VU=NnJ zvE0+N)s|G8$nsj2d;MQZ)8;iV6G|tUgSCYNa@jMhBgp?C_-_Uan&&pQHEX9gC!E7> z*(Rf|Fqp&gZkBV=`d(&SU1qQk>o&12&otE)1w$P@xs6-2lW#UaE@1mKwilXv>iPzY zSYF3+*nCn~5iDkT1j{8RT;D%f%JR7^mznAH1G39`L=)sKbNaGv0^9nTZS^I=2+Ols zt`I&)>N86#+5ZN4FP#32D`W|s0qlzx7Tp|ZdNdTMK^;AKn;|RPgI|BmH_yj|jTuBa zs)A35nKK)Tv*Vnx%q~oVZDnjrnk^0CoD|!Z%l&Yw*anR3)uyu{6s%zd{$$h6VDoK5 zNpJ|uds!Z8%0?8I4&&e%Ht}%A3gSlX)UqGzwNr;0!vmdq?CBxv*uah%NkL5@7Z$c&^Amq*rbA*H;B=j7~BnTuVAfN^sQCxKaIRfGe$#N{Z%Wi}f z#RCnLipnkmq9|V9c&sPhHy*+J2Jc(E?_=NU-sN$h{gdaduBxuL->U9!o_ugNeRwAI zRC`kM*2f-natpJvvT`$DIfMBA@Bluja3HTMY~q=Pe%@0!h_>*%h3$n~<9S(qCrq2X zaL%M<9gC1aS!x?kESfa%vW%|^c9z=yUvN2ZFG^--{j9Fw&nqe%6?3Pk9lWKuC`WSL zP3lU%H(KFKBxCLjbrl@NzBuqYwbQI8(=oSIUCrIaA-V?M0A0(?!;789n47PzV_jP2 zBpck>>Uy4CQtnG8V(xn7ayVGw#AB|bGG;l|5ObBf0XR%I^3<9NzO=+kH<&-V}4&)h!%O1*A}^y47+4uYkG@p@Zpm?kWw?9fnIP<{qc+^GPPi-{h zR;b5OyMp(Yd+7POxcE~cOOx$vPL^|K`m z@>S{=!xDs*`c-Bj8^@TzgCoJbCd@*&yUpFIi9}f+>c%vAL~q_7@lqezhWkf-lr2?R zMIG`AS)L5!2v;9y7ijVc*_yi+R%!KNa(iAz>;pY{7i9rc&vNImRiP%7k=o3W}6x z`f94+WYtj=Fb7RQsk1c&O}M-sQ#B2iUOQ>`I87mGmoM4mo~S8o_{q!-)D)3J^5kkK z7|l5Ha5_Wq$188JTMhg7Xn&KRfMJR!#3hs(Ilr+6;aFwQ%tqv+vG}YVcFrY>Qj1rlXahlRHJ<_0c zni@?z8{8^QO(r>s7!(xb!du+%U!iz(&nOJ+mNQI zvWZu|erX<2i=KiKS~ty9Mt{NRNF#7s&UqA=2DrJ-q3LE~K^bBlZAd}5MVfwRcz{#0 zrejb$LdQx4-e2dV3;2gM@b8WX_V7%rTLY7>I$nQ(0+|`=qn+7B#WP!Qr;EC&Tf)P?WkL$P4 zstSomYC6%-gsQkVe}KbKo}}p{Db1VXK3Zh!g6Awvi_LN<;iFD7$qn+Tbji5MgLg3> zA1~uwNLpeGg5Y_YmYN!1f_<0S;$Q-emP0{YCWblXPo%Pa>ETM<`hQ6%CEj-;8APi)E9hZj%ysOEsNpt_PO$HLc=H zlL1;S{gn?j`pc^Z4CH;Kxjqoa$ed<`0AX-kW7-YA(=?rKB!zIGbB3_wPg4%9wffh~ zFrI1jPs+tR%RD7eCCX2wz!Dlm?{iF}?cvs$5k%8L^;|P;;D?y=aE5?9(xWx?m_~!; z5>4xc3U@X*w80PoDX7avE|8s~>3q|awA-%f0wX%O;v!$TAswQP;1i~ccs}sO(gmKG z_R%GV54eH+CL?x}Q22+T0BTVCpJqAXI+`|vO_VM*8p}Px#BH(T0RxwQs~Pl^WNj1e zxu?-fmzkC)aR%(L-7tsDNWB~(A-cj4#aZyF+QDO+BDGiAU%6fKV0US{DqfJ)Z?gO@ zZtGmUxMS|J&LwbUW%Uw1Q9J+ho#{KYN7L1rf?isOb>M3RpKkHBf-kf9I)1e&$Zn`NSuN- zJuHXoengz}v4#UZD)@4kz>f*Oz~bG4|8DW)g3q$}3BfZgep2vh7C$9;tHr&7FSNz? zNO8fMp0g$xZU_ldI$YpD5#;Pp1}O$ijN@e3J& z6W$i*Dy$*!9l3MGhsEz@3f#vnd|#H??)8D}C0NskvX}ZuoI$K1|6{>xU;=+4 z_;{Q2sU!*3v|o}ojPa)Hv4XJACG4DDst5i;@OF#86nu%rUrD-PO~ zTfxmRfxi=chQ;3tKEmQ31TV1oN5OOK#y{bV+j?myQh$~jm>DSj3l}t({!vU1UnUQ zcgx_~o#N@A@yid&|E+jZ$Aa0*I<#kiY%oW{4&vP{gZ%@=-Y)ha{<2}Vi#HB zc?XE+d6u5gxdQLo($14QP_j5PKtyBhDdG09A%Cf)9wDh^eDc_8f4SIah+V-u#}4xc z#BLTl$a}{Q_YW3(f!HA~YOO5}OG74__sbIz-$e06`PkN|zf$a3Vh`c9t&z$qiA8Zd zTb^pc)n?c{LnRI`Dg=%3ldVBDEYn}67j})6<+s1HJ5Iz)jgt(QtZLc4mMhvK#dWe{ z#Egb#g!m%jQ+!lgxFjyVrRF|(65<2K?nyqkt-_y@g_ROq&o{S4{S9L85IfCpwM8l$ zCHZK(ag*R$m^i{niIa8hIT(W-uJeq-MDDhMqb0D^-Ho_00&`&jH{)ayp*<~ #include -#import #import + +#import #import #include "CoreFoundationBridge.h" From 36d17c9ea80f79389aed194bc70a46533d2f32f3 Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Mon, 30 Oct 2023 12:54:07 +0200 Subject: [PATCH 51/67] cleanup --- Frameworks/DesktopKit/NXTWorkspace.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Frameworks/DesktopKit/NXTWorkspace.h b/Frameworks/DesktopKit/NXTWorkspace.h index 5456c3da2..34b0758fe 100644 --- a/Frameworks/DesktopKit/NXTWorkspace.h +++ b/Frameworks/DesktopKit/NXTWorkspace.h @@ -21,7 +21,8 @@ #import -/* Notifications to communicate with applications. Manadatory prefixes in +/* + Notifications to communicate with applications. Manadatory prefixes in notification names are: - WMShould for notification from application to perform some action - WMDid to notify application about action completion @@ -29,14 +30,17 @@ All notifications object must be set to @"GSWorkspaceNotification". Otherwise Workspace Manager will ignore this notification. - All notifications must contain in userInfo: - "WindowID" = CFNumber; - "ApplicationName" = CFString; */ // WM.plist extern NSString* WMDidChangeAppearanceSettingsNotification; // WMState.plist extern NSString* WMDidChangeDockContentNotification; + +/* + All WMShould and WMDid notifications must contain in userInfo: + "WindowID" = CFNumber; + "ApplicationName" = CFString; + */ // Hide All extern NSString* WMShouldHideOthersNotification; extern NSString* WMDidHideOthersNotification; From 172b79dad1d726c913092b920ea91337c88a75e7 Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Mon, 30 Oct 2023 17:30:13 +0200 Subject: [PATCH 52/67] WM: add "UseAntialiasedText" setting. --- Applications/Workspace/WM/defaults.c | 26 +++++++++++++++++++++----- Applications/Workspace/WM/defaults.h | 20 +++++++++++--------- 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/Applications/Workspace/WM/defaults.c b/Applications/Workspace/WM/defaults.c index ddfa9609d..114155495 100644 --- a/Applications/Workspace/WM/defaults.c +++ b/Applications/Workspace/WM/defaults.c @@ -175,6 +175,8 @@ static WDECallbackUpdate setModifierKeyLabels; static WDECallbackConvert getCursor; static WDECallbackUpdate setCursor; +static WDECallbackUpdate setAntialiasedText; + /* * Tables to convert strings to enumeration values. * Values stored are char @@ -474,10 +476,9 @@ WDefaultEntry optionList[] = { {"MenuStyle", "normal", seMenuStyles, &wPreferences.menu_style, getEnum, setMenuStyle, NULL, NULL}, {"WidgetColor", "(solid, \"#aaaaaa\")", NULL, NULL, getTexture, setWidgetColor, NULL, NULL}, - {"IconBack", "(\"tpixmap\", \"/Library/Images/common_Tile.tiff\", \"#000000\")", NULL, NULL, - getTexture, setIconTile, NULL, NULL}, - {"MiniwindowBack", "(\"tpixmap\", \"/Library/Images/common_MiniWindowTile.tiff\", \"#000000\")", - NULL, NULL, getTexture, setMiniwindowTile, NULL, NULL}, /* NEXTSPACE */ + {"IconBack", DEF_ICON_BACK, NULL, NULL, getTexture, setIconTile, NULL, NULL}, + /* NEXTSPACE */ + {"MiniwindowBack", DEF_MINIWINDOW_BACK, NULL, NULL, getTexture, setMiniwindowTile, NULL, NULL}, {"TitleJustify", "center", seJustifications, &wPreferences.title_justification, getEnum, setJustify, NULL, NULL}, {"WindowTitleFont", DEF_TITLE_FONT, NULL, NULL, getFont, setWinTitleFont, NULL, NULL}, @@ -499,6 +500,7 @@ WDefaultEntry optionList[] = { {"MenuTextFont", DEF_MENU_ENTRY_FONT, NULL, NULL, getFont, setMenuTextFont, NULL, NULL}, {"IconTitleFont", DEF_ICON_TITLE_FONT, NULL, NULL, getFont, setIconTitleFont, NULL, NULL}, {"ClipTitleFont", DEF_CLIP_TITLE_FONT, NULL, NULL, getFont, setClipTitleFont, NULL, NULL}, + {"UseAntialiasedText", "NO", NULL, NULL, getBool, setAntialiasedText, NULL, NULL}, {"ShowClipTitle", "YES", NULL, &wPreferences.show_clip_title, getBool, NULL, NULL, NULL}, {"LargeDisplayFont", DEF_WORKSPACE_NAME_FONT, NULL, NULL, getFont, setLargeDisplayFont, NULL, NULL}, @@ -666,7 +668,6 @@ WDefaultEntry optionList[] = { {"CycleIgnoreMinimized", "NO", NULL, &wPreferences.cycle_ignore_minimized, getBool, NULL, NULL, NULL}}; - /* set `plkey` and `plvalue` fields of entries in `optionList` and `staticOptionList` */ static void _initializeOptionLists(void) { @@ -2630,6 +2631,21 @@ static int setLargeDisplayFont(WScreen *scr, WDefaultEntry *entry, void *tdata, return 0; } +static int setAntialiasedText(WScreen *scr, WDefaultEntry *entry, void *tdata, void *foo) +{ + char *flag = tdata; + + /* Parameter not used, but tell the compiler that it is ok */ + (void) entry; + (void) foo; + + scr->wmscreen->antialiasedText = *flag; + + fprintf(stderr, "setAntialiasedText: %s\n", (Bool)*flag ? "True" : "False"); + + return 0; +} + static int setHightlight(WScreen *scr, WDefaultEntry *entry, void *tdata, void *foo) { XColor *color = tdata; diff --git a/Applications/Workspace/WM/defaults.h b/Applications/Workspace/WM/defaults.h index 55dfd1dcf..e1c38e2ee 100644 --- a/Applications/Workspace/WM/defaults.h +++ b/Applications/Workspace/WM/defaults.h @@ -213,17 +213,17 @@ extern struct WPreferences { #ifdef USE_ICCCM_WMREPLACE unsigned int replace : 1; /* replace existing window manager */ #endif - unsigned int nodock : 1; /* don't display the dock */ - unsigned int noclip : 1; /* don't display the clip */ - unsigned int clip_merged_in_dock : 1; /* disable clip, switch workspaces with dock */ - unsigned int nodrawer : 1; /* don't use drawers */ + unsigned int nodock : 1; /* don't display the dock */ + unsigned int noclip : 1; /* don't display the clip */ + unsigned int clip_merged_in_dock : 1; /* disable clip, switch workspaces with dock */ + unsigned int nodrawer : 1; /* don't use drawers */ unsigned int wrap_appicons_in_dock : 1; /* Whether to wrap appicons when Dock is moved up and down */ - unsigned int noupdates : 1; /* don't require ~/GNUstep (-static) */ - unsigned int noautolaunch : 1; /* don't autolaunch apps */ - unsigned int norestore : 1; /* don't restore session */ - unsigned int restarting : 2; - } flags; /* internal flags */ + unsigned int noupdates : 1; /* don't require ~/GNUstep (-static) */ + unsigned int noautolaunch : 1; /* don't autolaunch apps */ + unsigned int norestore : 1; /* don't restore session */ + unsigned int restarting : 2; + } flags; /* internal flags */ /* Map table between w_cursor and actual X id */ Cursor cursor[WCUR_LAST]; @@ -256,6 +256,8 @@ void wDefaultsShouldTrackChanges(WDDomain *domain, Bool shouldTrack); #define DEF_WINDOW_TITLE_EXTEND_SPACE "0" #define DEF_MENU_TITLE_EXTEND_SPACE "0" #define DEF_MENU_TEXT_EXTEND_SPACE "0" +#define DEF_ICON_BACK "(\"tpixmap\", \"/Library/Images/common_Tile.tiff\", \"#000000\")" +#define DEF_MINIWINDOW_BACK "(\"tpixmap\", \"/Library/Images/common_MiniWindowTile.tiff\", \"#000000\")" #ifndef HAVE_INOTIFY /* Check defaults database for changes every this many milliseconds */ From f0ab682fafc2e9b30dcb76b0459cf3811ce1e55d Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Mon, 30 Oct 2023 17:31:27 +0200 Subject: [PATCH 53/67] remove old or commented code --- Applications/Workspace/WM/core/wfont.c | 3 --- Applications/Workspace/WM/core/wscreen.c | 3 +-- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/Applications/Workspace/WM/core/wfont.c b/Applications/Workspace/WM/core/wfont.c index bd2ca8e14..069a386a6 100644 --- a/Applications/Workspace/WM/core/wfont.c +++ b/Applications/Workspace/WM/core/wfont.c @@ -174,7 +174,6 @@ WMFont *WMCreateFont(WMScreen *scrPtr, const char *fontName) fname = wstrdup(fontName); } - /* if (!WINGsConfiguration.antialiasedText && !strstr(fname, ":antialias=")) { */ if (!scrPtr->antialiasedText && !strstr(fname, ":antialias=")) { fname = wstrappend(fname, ":antialias=false"); } @@ -199,9 +198,7 @@ WMFont *WMCreateFont(WMScreen *scrPtr, const char *fontName) font->height = font->font->ascent + font->font->descent; font->y = font->font->ascent; - font->refCount = 1; - font->name = fname; #ifdef USE_PANGO diff --git a/Applications/Workspace/WM/core/wscreen.c b/Applications/Workspace/WM/core/wscreen.c index 061cdb4ec..cd5ed353f 100644 --- a/Applications/Workspace/WM/core/wscreen.c +++ b/Applications/Workspace/WM/core/wscreen.c @@ -257,8 +257,7 @@ WMScreen *WMCreateScreenWithRContext(Display *display, int screen, RContext *con scrPtr->stipple = stipple; - /* scrPtr->antialiasedText = WINGsConfiguration.antialiasedText; */ - scrPtr->antialiasedText = False; /* TODO */ + scrPtr->antialiasedText = False; WMLogWarning("[TODO] Antialised text is set to false. No option exists to configure it."); scrPtr->normalFont = WMSystemFontOfSize(scrPtr, 0); From fb5fcc87fe6ae8d5b6cc58e08c407cfc65ab854f Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Mon, 30 Oct 2023 17:31:44 +0200 Subject: [PATCH 54/67] Preferences: use newly added WM's antialising option. --- Applications/Preferences/Modules/Font/Font.m | 35 +++++++++++--------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/Applications/Preferences/Modules/Font/Font.m b/Applications/Preferences/Modules/Font/Font.m index aed899e4c..1ee37a05f 100644 --- a/Applications/Preferences/Modules/Font/Font.m +++ b/Applications/Preferences/Modules/Font/Font.m @@ -195,31 +195,32 @@ static void setIntDefault(int anInt, NSString *name) return userDefPath; } -- (void)setWMFont:(NSFont *)font key:(NSString *)key +- (void)setWMPreference:(NSString *)value forKey:(NSString *)key { NSString *wmDefaultsPath = WWMDefaultsPath(); NSMutableDictionary *wmDefaults; - NSMutableString *value; if (![[NSFileManager defaultManager] fileExistsAtPath:wmDefaultsPath]) { - /* TODO: WM doesn't track WM.plist changes if it doesn't exist. - We need to send WMDidChangeWindowAppearanceSettings to the distributed - notification center (WM should handle this notification and reread file). */ NSLog(@"[Font] can't find existing WM defaults database! Creating new..."); wmDefaults = [NSMutableDictionary new]; } else { wmDefaults = [[NSMutableDictionary alloc] initWithContentsOfFile:wmDefaultsPath]; } + [wmDefaults setObject:value forKey:key]; + [wmDefaults writeToFile:wmDefaultsPath atomically:YES]; + [wmDefaults release]; +} + +- (void)setWMFont:(NSFont *)font forKey:(NSString *)key +{ + NSMutableString *value; + // Convert font name into the FontConfig format. value = [NSMutableString stringWithFormat:@"%@:postscriptname=%@:pixelsize=%.0f:antialias=%@", [font familyName], [font fontName], [font pointSize], [enableAntiAliasingButton state] ? @"true" : @"false"]; - // NSLog(@"[Font] set WM font %@ = `%@` -> (%@)", key, value, wmDefaultsPath); - - [wmDefaults setObject:value forKey:key]; - [wmDefaults writeToFile:wmDefaultsPath atomically:YES]; - [wmDefaults release]; + [self setWMPreference:value forKey:key]; } - (void)updateUI @@ -377,8 +378,12 @@ - (IBAction)setFont:(id)sender - (IBAction)enableAntiAliasingChanged:(id)sender { + // GS setBoolDefault([sender intValue], @"GSFontAntiAlias"); setIntDefault(0, @"back-art-subpixel-text"); + + // WM + [self setWMPreference:([sender intValue] ? @"YES" : @"NO") forKey:@"UseAntialiasedText"]; [self updateUI]; } @@ -425,9 +430,9 @@ - (void)changeFont:(id)sender setFloatDefault(fontSize - 3.0, @"NSMiniFontSize"); setFloatDefault(fontSize - 2.0, @"NSSmallFontSize"); // WM - [self setWMFont:font key:@"MenuTextFont"]; - [self setWMFont:[NSFont fontWithName:fontName size:fontSize - 3.0] key:@"IconTitleFont"]; - [self setWMFont:[NSFont fontWithName:fontName size:fontSize * 2.0] key:@"LargeDisplayFont"]; + [self setWMFont:font forKey:@"MenuTextFont"]; + [self setWMFont:[NSFont fontWithName:fontName size:fontSize - 3.0] forKey:@"IconTitleFont"]; + [self setWMFont:[NSFont fontWithName:fontName size:fontSize * 2.0] forKey:@"LargeDisplayFont"]; [[NSDistributedNotificationCenter defaultCenter] postNotificationName:WMDidChangeAppearanceSettingsNotification object:@"GSWorkspaceNotification"]; @@ -444,8 +449,8 @@ - (void)changeFont:(id)sender setStringDefault(fontName, @"NSPaletteFont"); setFloatDefault(fontSize, @"NSPaletteFontSize"); // WM - [self setWMFont:font key:@"MenuTitleFont"]; - [self setWMFont:font key:@"WindowTitleFont"]; + [self setWMFont:font forKey:@"MenuTitleFont"]; + [self setWMFont:font forKey:@"WindowTitleFont"]; [[NSDistributedNotificationCenter defaultCenter] postNotificationName:WMDidChangeAppearanceSettingsNotification object:@"GSWorkspaceNotification"]; From 3b916ecb0808e4ea97c610acd81e045ff45705e2 Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Mon, 30 Oct 2023 17:34:12 +0200 Subject: [PATCH 55/67] add new options to clang-format. --- .clang-format | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.clang-format b/.clang-format index ad5325b55..a2bbc1626 100644 --- a/.clang-format +++ b/.clang-format @@ -1,6 +1,8 @@ BasedOnStyle: Google AllowShortIfStatementsOnASingleLine: Never AllowShortLoopsOnASingleLine: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowAllConstructorInitializersOnNextLine: false AlwaysBreakBeforeMultilineStrings: false BreakBeforeBraces: Custom BraceWrapping: @@ -24,3 +26,6 @@ ColumnLimit: 100 SortIncludes: Never PointerAlignment: Right AlignConsecutiveBitFields: AcrossEmptyLinesAndComments +AlignTrailingComments: true +AlignEscapedNewlines: Left +AlignOperands: Align From 07a108788be94deb243a1fe18ec3dba0a5610be2 Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Mon, 30 Oct 2023 17:35:36 +0200 Subject: [PATCH 56/67] remved debug output --- Applications/Workspace/WM/defaults.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/Applications/Workspace/WM/defaults.c b/Applications/Workspace/WM/defaults.c index 114155495..0e669da1a 100644 --- a/Applications/Workspace/WM/defaults.c +++ b/Applications/Workspace/WM/defaults.c @@ -2641,8 +2641,6 @@ static int setAntialiasedText(WScreen *scr, WDefaultEntry *entry, void *tdata, v scr->wmscreen->antialiasedText = *flag; - fprintf(stderr, "setAntialiasedText: %s\n", (Bool)*flag ? "True" : "False"); - return 0; } From 352372cdcafafe6e5885627180e03f98542ebede Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Mon, 30 Oct 2023 18:43:53 +0200 Subject: [PATCH 57/67] remove warning as TODO was done. --- Applications/Workspace/WM/core/wscreen.c | 1 - 1 file changed, 1 deletion(-) diff --git a/Applications/Workspace/WM/core/wscreen.c b/Applications/Workspace/WM/core/wscreen.c index cd5ed353f..5b07bb968 100644 --- a/Applications/Workspace/WM/core/wscreen.c +++ b/Applications/Workspace/WM/core/wscreen.c @@ -258,7 +258,6 @@ WMScreen *WMCreateScreenWithRContext(Display *display, int screen, RContext *con scrPtr->stipple = stipple; scrPtr->antialiasedText = False; - WMLogWarning("[TODO] Antialised text is set to false. No option exists to configure it."); scrPtr->normalFont = WMSystemFontOfSize(scrPtr, 0); From f102e317750472cbb8410f2da37621265ba08cbe Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Tue, 31 Oct 2023 02:09:31 +0200 Subject: [PATCH 58/67] add local compile flags for C part of Workspace to omit clangd warnings. --- Applications/Workspace/WM/compile_flags.txt | 41 +++++++++++++++++++ .../Workspace/WM/core/compile_flags.txt | 1 + 2 files changed, 42 insertions(+) create mode 100644 Applications/Workspace/WM/compile_flags.txt create mode 120000 Applications/Workspace/WM/core/compile_flags.txt diff --git a/Applications/Workspace/WM/compile_flags.txt b/Applications/Workspace/WM/compile_flags.txt new file mode 100644 index 000000000..5f26959d0 --- /dev/null +++ b/Applications/Workspace/WM/compile_flags.txt @@ -0,0 +1,41 @@ +-xc +-MMD +-MP +-DGNUSTEP +-DGNUSTEP_BASE_LIBRARY=1 +-DGNU_GUI_LIBRARY=1 +-DGNUSTEP_RUNTIME=1 +-D_NONFRAGILE_ABI=1 +-DGNUSTEP_BASE_LIBRARY=1 +-fno-strict-aliasing +-fexceptions +-fobjc-exceptions +-D_NATIVE_OBJC_EXCEPTIONS +-DHAVE_CONFIG_H +-DWITH_GNUSTEP +-D_XOPEN_SOURCE=600 +-D_GNU_SOURCE +-pthread +-fPIC +-DDEBUG +-fno-omit-frame-pointer +-Wall +-Wno-import +-Wno-unused-variable +-Wno-typedef-redefinition +-g +-fobjc-runtime=gnustep-2.0 +-fblocks +-fconstant-string-class=NSConstantString +-I. +-I.. +-I/Users/me/Library/Headers +-I/Developer/Headers +-I/usr/NextSpace/include +-I/usr/include/freetype2 +-I/usr/include/libpng16 +-I/usr/include/harfbuzz +-I/usr/include/glib-2.0 +-I/usr/lib64/glib-2.0/include +-I/usr/include/sysprof-4 +-I/usr/include/libxml2 diff --git a/Applications/Workspace/WM/core/compile_flags.txt b/Applications/Workspace/WM/core/compile_flags.txt new file mode 120000 index 000000000..acd65fc91 --- /dev/null +++ b/Applications/Workspace/WM/core/compile_flags.txt @@ -0,0 +1 @@ +../compile_flags.txt \ No newline at end of file From 2ed25ec6003d80cd1b61dd547d46bf6d2556d73b Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Tue, 31 Oct 2023 02:09:58 +0200 Subject: [PATCH 59/67] removed extra code --- Applications/Workspace/Workspace+WM.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/Applications/Workspace/Workspace+WM.h b/Applications/Workspace/Workspace+WM.h index b616672e4..809aa6734 100644 --- a/Applications/Workspace/Workspace+WM.h +++ b/Applications/Workspace/Workspace+WM.h @@ -42,8 +42,6 @@ extern WorkspaceExitCode ws_quit_code; //----------------------------------------------------------------------------- #ifdef __OBJC__ -#undef _ - #include #include From 5206d23105eef38067571015ffc98b53784ff848 Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Tue, 31 Oct 2023 02:20:46 +0200 Subject: [PATCH 60/67] performFileOperation:source:destination:files:tag: implementation completed. --- Applications/Workspace/Controller+NSWorkspace.m | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/Applications/Workspace/Controller+NSWorkspace.m b/Applications/Workspace/Controller+NSWorkspace.m index 17878b248..ba3499489 100644 --- a/Applications/Workspace/Controller+NSWorkspace.m +++ b/Applications/Workspace/Controller+NSWorkspace.m @@ -36,6 +36,7 @@ #include #import +#include "Foundation/NSValue.h" #include "Foundation/NSBundle.h" #include "AppKit/NSImage.h" #import @@ -427,7 +428,7 @@ - (BOOL)openFile:(NSString *)fullPath //------------------------------------------------------------------------------------------------- //--- Manipulating Files //------------------------------------------------------------------------------------------------- -// FIXME: TODO +// Operation types supported by ProcessManager: Copy, Duplicate, Move, Link, Delete, Recycle - (BOOL)performFileOperation:(NSString*)operation source:(NSString*)source destination:(NSString*)destination @@ -451,8 +452,17 @@ - (BOOL)performFileOperation:(NSString*)operation } if (opType) { - [procManager startOperationWithType:opType source:source target:destination files:files]; - return YES; + id operation = [procManager startOperationWithType:opType + source:source + target:destination + files:files]; + if (operation) { + NSNumber *opHash = [NSNumber numberWithUnsignedInteger:[operation hash]]; + *tag = [opHash intValue]; + return YES; + } else { + return NO; + } } return NO; } From 29dcda30b137061d8a7c5563dceba781815d1917 Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Tue, 31 Oct 2023 02:31:07 +0200 Subject: [PATCH 61/67] use file operation types (strings) defined in AppKit/NSWorkspace.h. --- .../Workspace/Controller+NSWorkspace.h | 28 ++++++------------- .../Workspace/Controller+NSWorkspace.m | 23 ++++++++++----- 2 files changed, 25 insertions(+), 26 deletions(-) diff --git a/Applications/Workspace/Controller+NSWorkspace.h b/Applications/Workspace/Controller+NSWorkspace.h index 929a91235..bded96c91 100644 --- a/Applications/Workspace/Controller+NSWorkspace.h +++ b/Applications/Workspace/Controller+NSWorkspace.h @@ -154,28 +154,18 @@ //--- Manipulating Files //----------------------------------------------------------------------------- -//--- Possible values for operation in performFileOperation:... -APPKIT_EXPORT NSString *NSWorkspaceMoveOperation; -APPKIT_EXPORT NSString *NSWorkspaceCopyOperation; -APPKIT_EXPORT NSString *NSWorkspaceLinkOperation; -APPKIT_EXPORT NSString *NSWorkspaceCompressOperation; -APPKIT_EXPORT NSString *NSWorkspaceDecompressOperation; -APPKIT_EXPORT NSString *NSWorkspaceEncryptOperation; -APPKIT_EXPORT NSString *NSWorkspaceDecryptOperation; -APPKIT_EXPORT NSString *NSWorkspaceDestroyOperation; -APPKIT_EXPORT NSString *NSWorkspaceRecycleOperation; -APPKIT_EXPORT NSString *NSWorkspaceDuplicateOperation; - /** Requests the Workspace Manager to perform a file operation on a set of files in the source directory specifying the destination directory if needed using tag as an identifier for asynchronous operations; returns YES - if operation succeeded and NO otherwise.*/ -// TODO: [NSWorkspace _workspaceApplication] -// - (BOOL)performFileOperation:(NSString*)operation -// source:(NSString*)source -// destination:(NSString*)destination -// files:(NSArray*)files -// tag:(int*)tag; + if operation succeeded and NO otherwise. + + Strings for operation types defined in AppKit/NSWorkspace.h*/ +// --- [NSWorkspace _workspaceApplication] +- (BOOL)performFileOperation:(NSString *)operation + source:(NSString *)source + destination:(NSString *)destination + files:(NSArray *)files + tag:(int *)tag; /** Instructs Workspace Manager to select the file specified by fullPath opening a new file viewer if a path is specified by rootFullpath; returns diff --git a/Applications/Workspace/Controller+NSWorkspace.m b/Applications/Workspace/Controller+NSWorkspace.m index ba3499489..bcdda928d 100644 --- a/Applications/Workspace/Controller+NSWorkspace.m +++ b/Applications/Workspace/Controller+NSWorkspace.m @@ -36,6 +36,7 @@ #include #import +#include "AppKit/NSWorkspace.h" #include "Foundation/NSValue.h" #include "Foundation/NSBundle.h" #include "AppKit/NSImage.h" @@ -437,19 +438,27 @@ - (BOOL)performFileOperation:(NSString*)operation { OperationType opType = 0; - if ([operation isEqualToString:@"Copy"]) { + if ([operation isEqualToString:NSWorkspaceCopyOperation]) { opType = CopyOperation; - } else if ([operation isEqualToString:@"Duplicate"]) { + } else if ([operation isEqualToString:NSWorkspaceDuplicateOperation]) { opType = DuplicateOperation; - } else if ([operation isEqualToString:@"Move"]) { + } else if ([operation isEqualToString:NSWorkspaceMoveOperation]) { opType = MoveOperation; - } else if ([operation isEqualToString:@"Link"]) { + } else if ([operation isEqualToString:NSWorkspaceLinkOperation]) { opType = LinkOperation; - } else if ([operation isEqualToString:@"Delete"]) { + } else if ([operation isEqualToString:NSWorkspaceDestroyOperation]) { opType = DeleteOperation; - } else if ([operation isEqualToString:@"Recycle"]) { + } else if ([operation isEqualToString:NSWorkspaceRecycleOperation]) { opType = RecycleOperation; - } + } /*else if ([operation isEqualToString:NSWorkspaceCompressOperation]) { + opType = ; + } else if ([operation isEqualToString:NSWorkspaceDecompressOperation]) { + opType = ; + } else if ([operation isEqualToString:NSWorkspaceEncryptOperation]) { + opType = ; + } else if ([operation isEqualToString:NSWorkspaceDecryptOperation]) { + opType = ; + }*/ if (opType) { id operation = [procManager startOperationWithType:opType From 2610e2ddfd7281b77645ea16547a3cf784b81a24 Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Tue, 31 Oct 2023 02:35:08 +0200 Subject: [PATCH 62/67] enabled code for -fileSystemChanged and -noteFileSystemChanged methods. --- .../Workspace/Controller+NSWorkspace.h | 6 ++---- .../Workspace/Controller+NSWorkspace.m | 20 +++++++++---------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/Applications/Workspace/Controller+NSWorkspace.h b/Applications/Workspace/Controller+NSWorkspace.h index bded96c91..3b55e3bec 100644 --- a/Applications/Workspace/Controller+NSWorkspace.h +++ b/Applications/Workspace/Controller+NSWorkspace.h @@ -245,12 +245,10 @@ APPKIT_EXPORT NSString *NSShellCommandFileType; /** Returns whether a change to the file system has been registered with a noteFileSystemChanged message since the last fileSystemChanged message.*/ -// CHECK -// - (BOOL)fileSystemChanged; +- (BOOL)fileSystemChanged; /** Informs Workspace Manager that the file system has changed.*/ -// CHECK -// - (void)noteFileSystemChanged; +- (void)noteFileSystemChanged; //----------------------------------------------------------------------------- //--- Updating Registered Services and File Types diff --git a/Applications/Workspace/Controller+NSWorkspace.m b/Applications/Workspace/Controller+NSWorkspace.m index bcdda928d..999baa15e 100644 --- a/Applications/Workspace/Controller+NSWorkspace.m +++ b/Applications/Workspace/Controller+NSWorkspace.m @@ -781,18 +781,18 @@ - (NSImage *)iconForOpenedDirectory:(NSString *)fullPath //------------------------------------------------------------------------------------------------- //--- Tracking Changes to the File System //------------------------------------------------------------------------------------------------- -// - (BOOL)fileSystemChanged -// { -// BOOL flag = _fileSystemChanged; +- (BOOL)fileSystemChanged +{ + BOOL flag = _fileSystemChanged; -// _fileSystemChanged = NO; -// return flag; -// } + _fileSystemChanged = NO; + return flag; +} -// - (void)noteFileSystemChanged -// { -// _fileSystemChanged = YES; -// } +- (void)noteFileSystemChanged +{ + _fileSystemChanged = YES; +} //------------------------------------------------------------------------------------------------- //--- Updating Registered Services and File Types From 9d89ca94ace395130614deed466bcc6fdcb6264b Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Tue, 31 Oct 2023 15:20:06 +0200 Subject: [PATCH 63/67] Workspace: do not try to connect to X11 application after launch. --- .../Workspace/Controller+NSWorkspace.m | 47 +++++++++++-------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/Applications/Workspace/Controller+NSWorkspace.m b/Applications/Workspace/Controller+NSWorkspace.m index 999baa15e..189622f20 100644 --- a/Applications/Workspace/Controller+NSWorkspace.m +++ b/Applications/Workspace/Controller+NSWorkspace.m @@ -392,35 +392,46 @@ - (BOOL)openFile:(NSString *)fullPath NSBundle *appBundle; NSDictionary *appInfo; NSString *wmName; + NSString *wmClass; NSString *iconPath; NSString *launchPath; + launchPath = [self _locateApplicationBinary:appName]; + if (launchPath == nil) { + return NO; + } + appBundle = [self _bundleForApp:appName]; if (appBundle) { appInfo = [appBundle infoDictionary]; iconPath = [appBundle pathForImageResource:[appInfo objectForKey:@"NSIcon"]]; wmName = [appInfo objectForKey:@"NSExecutable"]; - launchPath = [self _locateApplicationBinary:appName]; - if (launchPath == nil) { - return NO; + wmClass = [wmName pathExtension]; + + if ([wmClass isEqualToString:@""] == NO) { + wmName = [wmName stringByDeletingPathExtension]; + } else { + wmClass = @"GNUstep"; } + [raceLock lock]; - wLaunchingAppIconCreate([[wmName stringByDeletingPathExtension] cString], "GNUstep", - [launchPath cString], point.x, point.y, [iconPath cString]); + wLaunchingAppIconCreate([wmName cString], [wmClass cString], [launchPath cString], point.x, + point.y, [iconPath cString]); [raceLock unlock]; - } - if (![self openFile:fullPath withApplication:appName andDeactivate:YES]) { - NXTRunAlertPanel(_(@"Workspace"), _(@"Failed to start application \"%@\" for file \"%@\""), - nil, nil, nil, appName, [fullPath lastPathComponent]); - return NO; - } - // If multiple files are opened at once we need to wait for app to start. - // Otherwise two copies of one application become alive. - while ([self _connectApplication:appName] == nil) { - [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.5]]; + if (![self openFile:fullPath withApplication:appName andDeactivate:YES]) { + NXTRunAlertPanel(_(@"Workspace"), _(@"Failed to start application \"%@\" for file \"%@\""), + nil, nil, nil, appName, [fullPath lastPathComponent]); + return NO; + } + // If multiple files are opened at once we need to wait for app to start. + // Otherwise two copies of one application become alive. + while (([wmClass isEqualToString:@"GNUstep"] != NO) && + ([self _connectApplication:appName] == nil)) { + [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.5]]; + } + return YES; } - return YES; } return NO; @@ -1395,9 +1406,7 @@ - (id)_connectApplication:(NSString *)appName if (host == nil) { host = @""; } else { - NSHost *h; - - h = [NSHost hostWithName:host]; + NSHost *h = [NSHost hostWithName:host]; if ([h isEqual:[NSHost currentHost]] == YES) { host = @""; } From 44633e3b19ccd6d22082afe731d62d5eb2e6a66e Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Tue, 31 Oct 2023 19:07:42 +0200 Subject: [PATCH 64/67] Workspace: first experiments with "Hide Others" feature. --- Applications/Workspace/Controller.m | 38 +++++++++------- Applications/Workspace/WM/application.c | 60 +++++++++++++++++-------- 2 files changed, 63 insertions(+), 35 deletions(-) diff --git a/Applications/Workspace/Controller.m b/Applications/Workspace/Controller.m index 36e530c15..4d337dae9 100644 --- a/Applications/Workspace/Controller.m +++ b/Applications/Workspace/Controller.m @@ -852,14 +852,6 @@ - (void)openFileViewerService:(NSPasteboard *)pboard } } -- (void)hideOtherApplications:(id)sender -{ - NSLog(@"hideOtherApplications"); - [[NSDistributedNotificationCenter defaultCenter] - postNotificationName:CF_NOTIFICATION(WMShouldHideOthersNotification) - object:@"GSWorkspaceNotification"]; -} - //============================================================================ // Access to Workspace data via NSApp //============================================================================ @@ -1047,8 +1039,22 @@ - (void)updateKeyboardBadge:(NSNotification *)aNotification // Application menu //============================================================================ +- (void)hideOtherApplications:(id)sender +{ + Window xWindow = (Window)[GSCurrentServer() windowDevice:[[NSApp keyWindow] windowNumber]]; + NSDictionary *info = + @{@"WindowID" : [NSNumber numberWithUnsignedLong:xWindow], @"ApplicationName" : @"Workspace"}; + + NSLog(@"hideOtherApplications for X window ID: %lu", xWindow); + + [[NSDistributedNotificationCenter defaultCenter] + postNotificationName:CF_NOTIFICATION(WMShouldHideOthersNotification) + object:@"GSWorkspaceNotification" + userInfo:info]; +} + // Info -- (void)showInfoPanel:sender +- (void)showInfoPanel:(id)sender { if (infoPanel == nil) { [NSBundle loadNibNamed:@"InfoPanel" owner:self]; @@ -1059,7 +1065,7 @@ - (void)showInfoPanel:sender [infoPanel makeKeyAndOrderFront:nil]; } -- (void)showLegalPanel:sender +- (void)showLegalPanel:(id)sender { if (legalPanel == nil) { NSScrollView *sv; @@ -1078,7 +1084,7 @@ - (void)showLegalPanel:sender } // TODO -- (void)saveLegalToFile:sender +- (void)saveLegalToFile:(id)sender { NSSavePanel *sp = [NXTSavePanel savePanel]; @@ -1154,7 +1160,7 @@ - (void)updateViewers:(id)sender } // Tools -> Inspector -- (void)showAttributesInspector:sender +- (void)showAttributesInspector:(id)sender { if (!inspector) { [self _loadInpectors]; @@ -1162,7 +1168,7 @@ - (void)showAttributesInspector:sender [inspector showAttributesInspector:self]; } -- (void)showContentsInspector:sender +- (void)showContentsInspector:(id)sender { if (!inspector) { [self _loadInpectors]; @@ -1170,7 +1176,7 @@ - (void)showContentsInspector:sender [inspector showContentsInspector:self]; } -- (void)showToolsInspector:sender +- (void)showToolsInspector:(id)sender { if (!inspector) { [self _loadInpectors]; @@ -1178,7 +1184,7 @@ - (void)showToolsInspector:sender [inspector showToolsInspector:self]; } -- (void)showPermissionsInspector:sender +- (void)showPermissionsInspector:(id)sender { if (!inspector) { [self _loadInpectors]; @@ -1217,7 +1223,7 @@ - (void)showConsole:(id)sender [console activate]; } -- (void)showLauncher:sender +- (void)showLauncher:(id)sender { if (launcher == nil) { launcher = [[Launcher alloc] init]; diff --git a/Applications/Workspace/WM/application.c b/Applications/Workspace/WM/application.c index d558b98bc..22902a47b 100644 --- a/Applications/Workspace/WM/application.c +++ b/Applications/Workspace/WM/application.c @@ -120,19 +120,37 @@ static void hideOthersObserver(CFNotificationCenterRef center, const void *object, // object - ignored CFDictionaryRef userInfo) { - CFNumberRef windowID = CFDictionaryGetValue(userInfo, CFSTR("WindowID")); - /* WApplication *observer_wapp = (WApplication *)wobserver; */ - /* WApplication *wapp; */ - Window window = 0; - WWindow *wwin; - - if (windowID) { - WMLogInfo("Will hide other applications for window %lu", window); - CFNumberGetValue(windowID, kCFNumberLongType, &window); - wwin = wWindowFor(window); - wApplicationHideOthers(wwin); - postWorkspaceNotification(wwin, WMDidHideOthersNotification); + CFStringRef appName = CFDictionaryGetValue(userInfo, CFSTR("ApplicationName")); + WApplication *wapp = (WApplication *)wobserver; + // CFNumberRef windowID = NULL; + // Window window = 0; + // WWindow *wwin = NULL; + + if (wApplicationOf(wapp->main_window) == NULL) { + WMLogCritical("You've forgot to remove CFNotificationObserver to WMShouldHideOthersNotification!!!"); + return; } + + if (CFStringCompare(appName, wapp->appName, 0) == 0) { + wApplicationHideOthers(wapp->main_wwin); + } + // if (CFStringCompare(appName, wapp->appName, 0)) { + // if (wapp->flags.hidden == 0) { + // // windowID = CFDictionaryGetValue(userInfo, CFSTR("WindowID")); + // // if (windowID) { + // // CFNumberGetValue(windowID, kCFNumberLongType, &window); + // // // WMLogInfo("Will hide other applications for window %lu", window); + // // wwin = wWindowFor(window); + // // } + // // wwin = wWindowFor(wapp->main_window); + // if (wapp->flags.is_gnustep && wapp->gsmenu_wwin) { + // WMLogInfo("send WM_HIDE_APP protocol message to client to %@.", wapp->appName); + // wClientSendProtocol(wapp->gsmenu_wwin, w_global.atom.gnustep.wm_hide_app, CurrentTime); + // } else { + // wApplicationHide(wapp); + // } + // } + // } } static WWindow *makeMainWindow(WScreen *scr, Window window) @@ -393,6 +411,10 @@ void wApplicationDestroy(WApplication *wapp) if (wapp->refcount > 0) return; + scr = wapp->main_wwin->screen; + + CFNotificationCenterRemoveEveryObserver(scr->notificationCenter, wapp); + CFArrayRemoveAllValues(wapp->windows); CFRelease(wapp->windows); /* WMLogError("wapp->windows retain count: %li", CFGetRetainCount(wapp->windows)); */ @@ -428,8 +450,6 @@ void wApplicationDestroy(WApplication *wapp) return; } - scr = wapp->main_wwin->screen; - // Notify Workspace's ProcessManager if (!wapp->flags.is_gnustep) { CFNotificationCenterPostNotification(scr->notificationCenter, @@ -610,6 +630,8 @@ void wApplicationHide(WApplication *wapp) return; } + WMLogWarning("wmApplicationHide() called for application `%@`", wapp->appName); + scr = wapp->main_wwin->screen; hadfocus = 0; wlist = scr->focused_window; @@ -625,10 +647,10 @@ void wApplicationHide(WApplication *wapp) /* Special treatment of Workspace: set focus to main menu prior to any window hiding to prevent searching for next focused window. Workspace's main menu will not be unmapped on hiding. */ - if (wapp->gsmenu_wwin && !strcmp(wapp->gsmenu_wwin->wm_instance, "Workspace")) { - XSetInputFocus(dpy, wapp->gsmenu_wwin->client_win, RevertToParent, CurrentTime); - is_workspace = True; - } + // if (wapp->gsmenu_wwin && !strcmp(wapp->gsmenu_wwin->wm_instance, "Workspace")) { + // XSetInputFocus(dpy, wapp->gsmenu_wwin->client_win, RevertToParent, CurrentTime); + // is_workspace = True; + // } while (wlist) { if (wlist->main_window == wapp->main_window && @@ -654,7 +676,7 @@ void wApplicationHide(WApplication *wapp) } wlist = wlist->prev; } - wSetFocusTo(scr, wlist); + // wSetFocusTo(scr, wlist); } wapp->flags.hidden = 1; From c0febb4e101430927c0064b6ea4734e34cfb3765 Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Wed, 1 Nov 2023 19:18:50 +0200 Subject: [PATCH 65/67] trying to make "Hide Others" working for Workspace --- Applications/Workspace/Controller.m | 2 - .../Workspace/Processes/ProcessManager.m | 2 +- Applications/Workspace/WM/application.c | 202 +++++++++++------- Applications/Workspace/WMNotificationCenter.m | 24 ++- 4 files changed, 136 insertions(+), 94 deletions(-) diff --git a/Applications/Workspace/Controller.m b/Applications/Workspace/Controller.m index 4d337dae9..d8314106f 100644 --- a/Applications/Workspace/Controller.m +++ b/Applications/Workspace/Controller.m @@ -1045,8 +1045,6 @@ - (void)hideOtherApplications:(id)sender NSDictionary *info = @{@"WindowID" : [NSNumber numberWithUnsignedLong:xWindow], @"ApplicationName" : @"Workspace"}; - NSLog(@"hideOtherApplications for X window ID: %lu", xWindow); - [[NSDistributedNotificationCenter defaultCenter] postNotificationName:CF_NOTIFICATION(WMShouldHideOthersNotification) object:@"GSWorkspaceNotification" diff --git a/Applications/Workspace/Processes/ProcessManager.m b/Applications/Workspace/Processes/ProcessManager.m index 0e8cc50df..a325cc11e 100644 --- a/Applications/Workspace/Processes/ProcessManager.m +++ b/Applications/Workspace/Processes/ProcessManager.m @@ -250,7 +250,7 @@ - (void)applicationDidTerminate:(NSNotification *)notif - (void)applicationDidBecomeActive:(NSNotification *)notif { - WMLogWarning("ApplicationDidBecomeActive: %@", convertNStoCFDictionary([notif userInfo])); + // WMLogWarning("ApplicationDidBecomeActive: %@", convertNStoCFDictionary([notif userInfo])); _activeApplication = [[notif userInfo] copy]; } diff --git a/Applications/Workspace/WM/application.c b/Applications/Workspace/WM/application.c index 22902a47b..6fa01994f 100644 --- a/Applications/Workspace/WM/application.c +++ b/Applications/Workspace/WM/application.c @@ -114,6 +114,45 @@ static void shadeObserver(CFNotificationCenterRef center, } } +static void hideObserver(CFNotificationCenterRef center, + void *wobserver, // wapp + CFNotificationName name, + const void *object, // object - ignored + CFDictionaryRef userInfo) +{ + WApplication *wapp = (WApplication *)wobserver; + CFStringRef appName = CFDictionaryGetValue(userInfo, CFSTR("NSApplicationName")); + + if (!appName || CFStringCompare(appName, wapp->appName, 0) != 0) { + // Unknown application or application is not observed object + // WMLogInfo("hideObserver: `%@` application is not observed object - %@.", + // appName, wapp->appName); + return; + } + + wapp->flags.hidden = 1; + WMLogInfo("hideObserver: %@ did HIDE.", wapp->appName); +} + +static void unhideObserver(CFNotificationCenterRef center, + void *wobserver, // wapp + CFNotificationName name, + const void *object, // object - ignored + CFDictionaryRef userInfo) +{ + WApplication *wapp = (WApplication *)wobserver; + CFStringRef appName = CFDictionaryGetValue(userInfo, CFSTR("NSApplicationName")); + + if (!appName || CFStringCompare(appName, wapp->appName, 0) != 0) { + // Unknown application or application is not observed object + // WMLogInfo("unhideObserver: `%@` application is not observed object - %@.", + // appName, wapp->appName); + return; + } + wapp->flags.hidden = 0; + WMLogInfo("unhideObserver: %@ did UNHIDE.", wapp->appName); +} + static void hideOthersObserver(CFNotificationCenterRef center, void *wobserver, // wapp CFNotificationName name, @@ -122,35 +161,15 @@ static void hideOthersObserver(CFNotificationCenterRef center, { CFStringRef appName = CFDictionaryGetValue(userInfo, CFSTR("ApplicationName")); WApplication *wapp = (WApplication *)wobserver; - // CFNumberRef windowID = NULL; - // Window window = 0; - // WWindow *wwin = NULL; if (wApplicationOf(wapp->main_window) == NULL) { - WMLogCritical("You've forgot to remove CFNotificationObserver to WMShouldHideOthersNotification!!!"); + // WMLogCritical("You've forgot to remove CFNotificationObserver to WMShouldHideOthersNotification!!!"); return; } if (CFStringCompare(appName, wapp->appName, 0) == 0) { wApplicationHideOthers(wapp->main_wwin); } - // if (CFStringCompare(appName, wapp->appName, 0)) { - // if (wapp->flags.hidden == 0) { - // // windowID = CFDictionaryGetValue(userInfo, CFSTR("WindowID")); - // // if (windowID) { - // // CFNumberGetValue(windowID, kCFNumberLongType, &window); - // // // WMLogInfo("Will hide other applications for window %lu", window); - // // wwin = wWindowFor(window); - // // } - // // wwin = wWindowFor(wapp->main_window); - // if (wapp->flags.is_gnustep && wapp->gsmenu_wwin) { - // WMLogInfo("send WM_HIDE_APP protocol message to client to %@.", wapp->appName); - // wClientSendProtocol(wapp->gsmenu_wwin, w_global.atom.gnustep.wm_hide_app, CurrentTime); - // } else { - // wApplicationHide(wapp); - // } - // } - // } } static WWindow *makeMainWindow(WScreen *scr, Window window) @@ -308,8 +327,6 @@ WApplication *wApplicationCreate(WWindow *wwin) wapp->appName = CFStringCreateWithCString(kCFAllocatorDefault, wwin->wm_class, kCFStringEncodingUTF8); } - /* wapp->app_name = wwin->flags.is_gnustep ? wstrdup(wwin->wm_instance) : wstrdup(wwin->wm_class); - */ wApplicationAddWindow(wapp, wwin); @@ -374,6 +391,12 @@ WApplication *wApplicationCreate(WWindow *wwin) CFNotificationCenterAddObserver(scr->notificationCenter, wapp, hideOthersObserver, WMShouldHideOthersNotification, NULL, CFNotificationSuspensionBehaviorDeliverImmediately); + // CFNotificationCenterAddObserver(scr->notificationCenter, wapp, hideObserver, + // CFSTR("NSApplicationDidHideNotification"), NULL, + // CFNotificationSuspensionBehaviorDeliverImmediately); + // CFNotificationCenterAddObserver(scr->notificationCenter, wapp, unhideObserver, + // CFSTR("NSApplicationDidUnhideNotification"), NULL, + // CFNotificationSuspensionBehaviorDeliverImmediately); // Notify Workspace's ProcessManager CFNotificationCenterPostNotification(scr->notificationCenter, @@ -580,7 +603,7 @@ static inline void flushExpose(void) XSync(dpy, 0); } -static void hideWindow(WIcon *icon, int icon_x, int icon_y, WWindow *wwin) +static void _hideWindow(WIcon *icon, int icon_x, int icon_y, WWindow *wwin) { if (wwin->flags.miniaturized) { if (wwin->icon) { @@ -617,9 +640,9 @@ static void hideWindow(WIcon *icon, int icon_x, int icon_y, WWindow *wwin) void wApplicationHide(WApplication *wapp) { WScreen *scr; - WWindow *wlist; + WWindow *list_wwin; int hadfocus; - Bool is_workspace = False; + Bool wapp_is_workspace = False; if (!wapp) { WMLogWarning("trying to hide a non grouped window"); @@ -630,16 +653,25 @@ void wApplicationHide(WApplication *wapp) return; } - WMLogWarning("wmApplicationHide() called for application `%@`", wapp->appName); + WMLogWarning("wApplicationHide(%@)", wapp->appName); + + if (wapp->flags.hidden) { + WMLogWarning("trying to hide already hidden application `%@`", wapp->appName); + return; + } scr = wapp->main_wwin->screen; hadfocus = 0; - wlist = scr->focused_window; - if (!wlist) { + list_wwin = scr->focused_window; + if (!list_wwin) { + WMLogWarning("(wmApplicationHide) no focused window for app `%@`", wapp->appName); return; } - if (wlist->main_window == wapp->main_window) { - wapp->last_focused = wlist; + + wapp->flags.skip_next_animation = 1; + + if (list_wwin->main_window == wapp->main_window) { + wapp->last_focused = list_wwin; } else { wapp->last_focused = NULL; } @@ -647,40 +679,47 @@ void wApplicationHide(WApplication *wapp) /* Special treatment of Workspace: set focus to main menu prior to any window hiding to prevent searching for next focused window. Workspace's main menu will not be unmapped on hiding. */ - // if (wapp->gsmenu_wwin && !strcmp(wapp->gsmenu_wwin->wm_instance, "Workspace")) { - // XSetInputFocus(dpy, wapp->gsmenu_wwin->client_win, RevertToParent, CurrentTime); - // is_workspace = True; - // } - - while (wlist) { - if (wlist->main_window == wapp->main_window && - (is_workspace == False || wlist != wapp->gsmenu_wwin)) { - if (wlist->flags.focused) { + if (wapp->flags.is_gnustep && !CFStringCompare(wapp->appName, CFSTR("Workspace"), 0)) { + XSetInputFocus(dpy, wapp->gsmenu_wwin->client_win, RevertToParent, CurrentTime); + wapp_is_workspace = True; + } + + // Perform windows hiding + while (list_wwin) { + if (list_wwin->main_window == wapp->main_window) { + if (list_wwin->flags.focused) { hadfocus = 1; } - if (wapp->app_icon) { - hideWindow(wapp->app_icon->icon, wapp->app_icon->x_pos, wapp->app_icon->y_pos, wlist); + if (wapp->app_icon && (wapp_is_workspace == False || list_wwin != wapp->gsmenu_wwin)) { + WMLogInfo("Hiding window %lu (%s) of %s", list_wwin->client_win, + (WINDOW_LEVEL(list_wwin) == NSMainMenuWindowLevel) ? "menu" : "window", + list_wwin->wm_instance); + _hideWindow(wapp->app_icon->icon, wapp->app_icon->x_pos, wapp->app_icon->y_pos, list_wwin); } } - wlist = wlist->prev; + list_wwin = list_wwin->prev; } + wapp->flags.hidden = 1; + wapp->flags.skip_next_animation = 0; - if (hadfocus && is_workspace == False) { - wlist = scr->focused_window; - while (wlist) { - if (!WFLAGP(wlist, no_focusable) && !wlist->flags.hidden && - (wlist->flags.mapped || wlist->flags.shaded)) { + if (hadfocus && wapp_is_workspace == False) { + list_wwin = scr->focused_window; + // WMLogInfo("(wApplicationHide:) searching for window to focus... focused: %s", scr->focused_window->wm_instance); + while (list_wwin) { + if (!WFLAGP(list_wwin, no_focusable) && !list_wwin->flags.hidden && + (list_wwin->flags.mapped || list_wwin->flags.shaded)) { break; } - wlist = wlist->prev; + list_wwin = list_wwin->prev; + } + if (list_wwin) { + WMLogInfo("(wApplicationHide:) Setting focus to window: %s", list_wwin->wm_instance); + wSetFocusTo(scr, list_wwin); } - // wSetFocusTo(scr, wlist); } - wapp->flags.hidden = 1; - if (wPreferences.auto_arrange_icons) { wArrangeIcons(scr, True); } @@ -691,41 +730,44 @@ void wApplicationHide(WApplication *wapp) #endif } -void wApplicationHideOthers(WWindow *awin) +void wApplicationHideOthers(WWindow *wwin) { - WWindow *wwin; + WWindow *list_wwin; + WApplication *list_wapp; WApplication *wapp; - WApplication *tapp; - if (!awin) + if (!wwin) { return; - wwin = awin->screen->focused_window; - wapp = wApplicationOf(wwin->main_window); - - while (wwin) { - tapp = wApplicationOf(wwin->main_window); - if (wwin != awin && tapp != wapp && wwin->frame->desktop == awin->screen->current_desktop && - !(wwin->flags.miniaturized || wwin->flags.hidden) && !wwin->flags.internal_window && - !WFLAGP(wwin, no_hide_others)) { - if (tapp != wapp && wwin->protocols.HIDE_APP) { - /* WMLogInfo("send WM_HIDE_APP protocol message to client."); */ - wClientSendProtocol(wwin, w_global.atom.gnustep.wm_hide_app, CurrentTime); - } else if (wwin->main_window == None || WFLAGP(wwin, no_appicon)) { - if (!WFLAGP(wwin, no_miniaturizable)) { - wwin->flags.skip_next_animation = 1; - wIconifyWindow(wwin); - } - } else if (wwin->main_window != None && awin->main_window != wwin->main_window) { - if (tapp) { - tapp->flags.skip_next_animation = 1; - wApplicationHide(tapp); - } else if (!WFLAGP(wwin, no_miniaturizable)) { - wwin->flags.skip_next_animation = 1; - wIconifyWindow(wwin); + } + list_wwin = wwin->screen->focused_window; + wapp = wApplicationOf(list_wwin->main_window); + + WMLogWarning("wApplicationHideOthers(%@)", wapp->appName); + + while (list_wwin) { + list_wapp = wApplicationOf(list_wwin->main_window); + if (list_wapp != wapp && list_wwin->frame->desktop == wwin->screen->current_desktop && + !(list_wwin->flags.miniaturized || list_wwin->flags.hidden) && + !list_wwin->flags.internal_window) { + if (list_wapp && list_wwin->main_window != None && + list_wwin->main_window != wwin->main_window) { + if (list_wwin->protocols.HIDE_APP) { + // Inform client about hiding. + // Normally WMFHideApplication comes from application (GNUstep) - it's a one call to + // wApplicationHide() through handleClientMessage() (event.c). + // In this case we hide app windows on previous line and send client message to draw + // hidden dot on appicon. This leads to second call to wApplicationHide(). + wClientSendProtocol(list_wwin, w_global.atom.gnustep.wm_hide_app, CurrentTime); + } else { + wApplicationHide(list_wapp); } + } else if ((list_wwin->main_window == None || WFLAGP(list_wwin, no_appicon)) && + !WFLAGP(list_wwin, no_miniaturizable)) { + list_wwin->flags.skip_next_animation = 1; + wIconifyWindow(list_wwin); } } - wwin = wwin->prev; + list_wwin = list_wwin->prev; } } diff --git a/Applications/Workspace/WMNotificationCenter.m b/Applications/Workspace/WMNotificationCenter.m index c92ac5f22..5f3a0c970 100644 --- a/Applications/Workspace/WMNotificationCenter.m +++ b/Applications/Workspace/WMNotificationCenter.m @@ -79,7 +79,7 @@ - (void)_postCFNotification:(NSString *)name userInfo:(NSDictionary *)info // userInfo cfUserInfo = convertNStoCFDictionary(info); - WMLogWarning("[WMNC] post CF notification: %@ - %@", cfName, cfUserInfo); + // WMLogWarning("post CF notification: %@", cfName); CFNotificationCenterPostNotification(_coreFoundationCenter, cfName, self, cfUserInfo, TRUE); @@ -104,7 +104,7 @@ static void _handleCFNotification(CFNotificationCenterRef center, void *observer // This is the mirrored notification sent by us if (object == _windowManagerCenter) { - WMLogWarning("_handleCFNotification: Received mirrored notification from CF. Ignoring..."); + WMLogWarning("handle CF notification: Received mirrored notification from CF. Ignoring..."); return; } @@ -116,8 +116,7 @@ static void _handleCFNotification(CFNotificationCenterRef center, void *observer nsUserInfo = convertCFtoNSDictionary(userInfo); } - WMLogWarning("[WMNC] _handleCFNotificaition: dispatching CF notification %@ - %@", name, - userInfo); + WMLogWarning("handle CF notificaition: Dispatching %@ - %@", name, userInfo); [_windowManagerCenter postNotificationName:nsName object:nsObject userInfo:nsUserInfo]; @@ -142,18 +141,21 @@ - (void)_handleRemoteNotification:(NSNotification *)aNotification objectName = object; } - if ([name isEqualToString:@"NSApplicationDidResignActiveNotification"] || - [name isEqualToString:@"NSApplicationDidBecomeActiveNotification"]) { + if ([name hasPrefix:@"NSApplication"]) { NSString *appName = [aNotification userInfo][@"NSApplicationName"]; - WMLogWarning("[WMNC] %s - %s", [aNotification name].cString, appName.cString); + WMLogWarning("handle remote notification: %s - %s", [aNotification name].cString, appName.cString); } else { - WMLogWarning("[WMNC] handle remote notification: %@ - %@", convertNStoCFString(name), + WMLogWarning("handle remote notification: %@ - %@", convertNStoCFString(name), convertNStoCFString(objectName)); } - if ([name hasPrefix:@"WM"]) { - [self _postCFNotification:name userInfo:[aNotification userInfo]]; - } else { + // Post all notifications to CFNotificationCenter + [self _postCFNotification:name userInfo:[aNotification userInfo]]; + + // if ([name hasPrefix:@"WM"]) { + // [self _postCFNotification:name userInfo:[aNotification userInfo]]; + // } else { + if ([name hasPrefix:@"WM"] == NO) { // Examples: // NSWorkspaceWillLaunchApplicationNotification - by Controller+NSWorkspace // NSWorkspaceDidLaunchApplicationNotification - by AppKit From 549701e3194be7970d1fb4f5377cc404c057408c Mon Sep 17 00:00:00 2001 From: Sergii Stoian Date: Thu, 2 Nov 2023 01:32:22 +0200 Subject: [PATCH 66/67] WM/application: wApplicationActivate(): remember focused window and always send notification; (wApplicationHideOthers()): don't send WMFHideOtherApplications client message for Workspace - call wApplicationHide() and send WMFHideOtherApplications for other GNUstep apps. Enable hide/unhide notification observers back. --- Applications/Workspace/WM/application.c | 48 ++++++++++++------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/Applications/Workspace/WM/application.c b/Applications/Workspace/WM/application.c index 6fa01994f..31cfd144f 100644 --- a/Applications/Workspace/WM/application.c +++ b/Applications/Workspace/WM/application.c @@ -172,6 +172,8 @@ static void hideOthersObserver(CFNotificationCenterRef center, } } + + static WWindow *makeMainWindow(WScreen *scr, Window window) { WWindow *wwin; @@ -391,12 +393,12 @@ WApplication *wApplicationCreate(WWindow *wwin) CFNotificationCenterAddObserver(scr->notificationCenter, wapp, hideOthersObserver, WMShouldHideOthersNotification, NULL, CFNotificationSuspensionBehaviorDeliverImmediately); - // CFNotificationCenterAddObserver(scr->notificationCenter, wapp, hideObserver, - // CFSTR("NSApplicationDidHideNotification"), NULL, - // CFNotificationSuspensionBehaviorDeliverImmediately); - // CFNotificationCenterAddObserver(scr->notificationCenter, wapp, unhideObserver, - // CFSTR("NSApplicationDidUnhideNotification"), NULL, - // CFNotificationSuspensionBehaviorDeliverImmediately); + CFNotificationCenterAddObserver(scr->notificationCenter, wapp, hideObserver, + CFSTR("NSApplicationDidHideNotification"), NULL, + CFNotificationSuspensionBehaviorDeliverImmediately); + CFNotificationCenterAddObserver(scr->notificationCenter, wapp, unhideObserver, + CFSTR("NSApplicationDidUnhideNotification"), NULL, + CFNotificationSuspensionBehaviorDeliverImmediately); // Notify Workspace's ProcessManager CFNotificationCenterPostNotification(scr->notificationCenter, @@ -524,22 +526,21 @@ void wApplicationActivate(WApplication *wapp) wApplicationMakeFirst(wapp); - if (wapp->flags.is_gnustep || wapp->app_menu->flags.mapped) { - return; - } - - if (wapp->menus_state && !wapp->app_menu->flags.restored) { - wApplicationMenuRestoreFromState(wapp->app_menu, wapp->menus_state); - wapp->app_menu->flags.restored = 1; - } else if (wapp->app_menu->flags.hidden) { - wApplicationMenuShow(wapp->app_menu); - } else { - wMenuMap(wapp->app_menu); - } + if (!wapp->flags.is_gnustep && !wapp->app_menu->flags.mapped) { + if (wapp->menus_state && !wapp->app_menu->flags.restored) { + wApplicationMenuRestoreFromState(wapp->app_menu, wapp->menus_state); + wapp->app_menu->flags.restored = 1; + } else if (wapp->app_menu->flags.hidden) { + wApplicationMenuShow(wapp->app_menu); + } else { + wMenuMap(wapp->app_menu); + } - if (!wapp->appState) { - wapp->appState = CFDictionaryCreateMutable( - kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + if (!wapp->appState) { + wapp->appState = CFDictionaryCreateMutable( + kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + } + wapp->last_focused = scr->focused_window; } if (scr->notificationCenter) { @@ -751,15 +752,14 @@ void wApplicationHideOthers(WWindow *wwin) !list_wwin->flags.internal_window) { if (list_wapp && list_wwin->main_window != None && list_wwin->main_window != wwin->main_window) { - if (list_wwin->protocols.HIDE_APP) { + wApplicationHide(list_wapp); + if (list_wwin->protocols.HIDE_APP && CFStringCompare(list_wapp->appName, CFSTR("Workspace"), 0)) { // Inform client about hiding. // Normally WMFHideApplication comes from application (GNUstep) - it's a one call to // wApplicationHide() through handleClientMessage() (event.c). // In this case we hide app windows on previous line and send client message to draw // hidden dot on appicon. This leads to second call to wApplicationHide(). wClientSendProtocol(list_wwin, w_global.atom.gnustep.wm_hide_app, CurrentTime); - } else { - wApplicationHide(list_wapp); } } else if ((list_wwin->main_window == None || WFLAGP(list_wwin, no_appicon)) && !WFLAGP(list_wwin, no_miniaturizable)) { From 5bfe64a33f0d451f632010327740879e93de0d19 Mon Sep 17 00:00:00 2001 From: MagnetarRocket <53055079+MagnetarRocket@users.noreply.github.com> Date: Mon, 24 Mar 2025 11:53:08 -0500 Subject: [PATCH 67/67] Add in bit that the fabled OpenStep PR1 won't be emulated. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index b89e3d4cf..94afcb03d 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ Unlike other 'real' and 'serious' projects, I have not yet defined a target audi * Porting to other Linux distributions and operating systems. For now, I want a fast, accurate, and stable version for RedHat-based Linux distributions. Currently these are CentOS 7, CentOS Stream and Fedora. However, NEXTSPACE was designed to be portable and thus this point may be changed in future. * GNOME, KDE, macOS rival in terms of visual effects, modern design principles, look and feel. * Implementing a macOS-like desktop paradigm. There is another good place for this -- see [Étoilé](http://etoileos.com). +* Creating a OpenStep 4.0 pr1-like desktop. ## Installing Installation is based off CentOS 7's minimal install, you can find [full directions in the installation guide](https://github.com/trunkmaster/nextspace/wiki/Install-Guide).