/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*- AZStartupHandler.m for the Azalea window manager Copyright (c) 2006 Yen-Ju Chen startupnotify.c for the Openbox window manager Copyright (c) 2003 Ben Jansens This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. See the COPYING file for a copy of the GNU General Public License. */ #import "AZStartupHandler.h" static AZStartupHandler *sharedInstance; #ifndef USE_LIBSN @implementation AZStartupHandler - (void) processXEvent: (XEvent *) e {} - (void) startup: (BOOL) reconfig {} - (void) shutdown: (BOOL) reconfig {} - (BOOL) applicationStarting { return NO; } - (void) applicationStarted: (char *) wmclass {} - (BOOL) getDesktop: (unsigned int *) desktop forIdentifier: (char *) iden { return NO; } - (id) copyWithZone: (NSZone *) zone { return RETAIN(self); } + (AZStartupHandler *) defaultHandler { if (sharedInstance == nil) { sharedInstance = [[AZStartupHandler alloc] init]; } return sharedInstance; } @end #else #import "openbox.h" #import "AZMainLoop.h" #import "AZScreen.h" @interface AZWaitData: NSObject { SnStartupSequence *seq; BOOL feedback; } - (SnStartupSequence *) seq; - (BOOL) feedback; - (void) set_seq: (SnStartupSequence *) seq; - (void) set_feedback: (BOOL) feedback; @end @implementation AZWaitData - (SnStartupSequence *) seq { return seq; } - (BOOL) feedback { return feedback; } - (void) set_seq: (SnStartupSequence *) s { seq = s; } - (void) set_feedback: (BOOL) f { feedback = f; } @end /* callback */ static void sn_event_func(SnMonitorEvent *event, void *data); @interface AZStartupHandler (AZPrivate) - (AZWaitData* ) waitDataNew: (SnStartupSequence *)seq; - (void) waitDataFree: (AZWaitData *) d; - (AZWaitData*) waitFind: (const char *) iden; /* ObjC version of callback in C */ - (void) snEventFunc: (SnMonitorEvent *) event data: (void *) data; - (BOOL) snWaitTimeout: (id) data; - (void) snWaitDestroy: (id) data; @end @implementation AZStartupHandler /* sn_handler */ - (void) processXEvent: (XEvent *) e { XEvent ec; ec = *e; sn_display_process_event(sn_display, &ec); } - (void) startup: (BOOL) reconfig { if (reconfig) return; sn_display = sn_display_new(ob_display, NULL, NULL); sn_context = sn_monitor_context_new(sn_display, ob_screen, sn_event_func, NULL, NULL); sn_waits = [[NSMutableArray alloc] init]; [[AZMainLoop mainLoop] addXHandler: self]; } - (void) shutdown: (BOOL) reconfig { if (reconfig) return; [[AZMainLoop mainLoop] removeXHandler: self]; int i, count = [sn_waits count]; for (i = 0; i < count; i++) { [self waitDataFree: [sn_waits objectAtIndex: i]]; } DESTROY(sn_waits); [[AZScreen defaultScreen] setRootCursor]; sn_monitor_context_unref(sn_context); sn_display_unref(sn_display); } - (BOOL) applicationStarting { int i, count = [sn_waits count]; for (i = 0; i < count; i++) { AZWaitData *d = [sn_waits objectAtIndex: i];; if ([d feedback]) return YES; } return NO; } - (void) applicationStarted: (char *) wmclass { int i, count = [sn_waits count]; for (i = 0; i < count; i++) { AZWaitData *d = [sn_waits objectAtIndex: i]; if (sn_startup_sequence_get_wmclass([d seq]) && !strcmp(sn_startup_sequence_get_wmclass([d seq]), wmclass)) { sn_startup_sequence_complete([d seq]); break; } } } - (BOOL) getDesktop: (unsigned int *) desktop forIdentifier: (char *) iden { AZWaitData *d; if (iden && (d = [self waitFind: iden])) { int desk = sn_startup_sequence_get_workspace([d seq]); if (desk != -1) { *desktop = desk; return YES; } } return NO; } - (id) copyWithZone: (NSZone *) zone { return RETAIN(self); } + (AZStartupHandler *) defaultHandler { if (sharedInstance == nil) { sharedInstance = [[AZStartupHandler alloc] init]; } return sharedInstance; } @end @implementation AZStartupHandler (AZPrivate) - (AZWaitData *) waitDataNew: (SnStartupSequence *) seq { AZWaitData *d = [[AZWaitData alloc] init]; [d set_seq: seq]; [d set_feedback: YES]; sn_startup_sequence_ref([d seq]); return d; } - (void) waitDataFree: (AZWaitData *) d; { if (d) { sn_startup_sequence_unref([d seq]); DESTROY(d); } } - (AZWaitData*) waitFind: (const char *) iden; { AZWaitData *ret = nil; int i, count = [sn_waits count]; for (i = 0; i < count; i++) { AZWaitData *d = [sn_waits objectAtIndex: i]; if (!strcmp(iden, sn_startup_sequence_get_id([d seq]))) { ret = d; break; } } return ret; } - (BOOL) snWaitTimeout: (id) data; { AZWaitData *d = data; [d set_feedback: NO]; [[AZScreen defaultScreen] setRootCursor]; return NO; /* don't repeat */ } - (void) snWaitDestroy: (id) data; { AZWaitData *d = data; [sn_waits removeObject: d]; [self waitDataFree: d]; } - (void) snEventFunc: (SnMonitorEvent *) ev data: (void *) data; { SnStartupSequence *seq; BOOL change = NO; AZWaitData *d; if (!(seq = sn_monitor_event_get_startup_sequence(ev))) return; AZMainLoop *mainLoop = [AZMainLoop mainLoop]; switch (sn_monitor_event_get_type(ev)) { case SN_MONITOR_EVENT_INITIATED: d = [self waitDataNew: seq]; [sn_waits insertObject: d atIndex: 0]; /* 30 second timeout for apps to start */ [mainLoop addTimeout: self handler: @selector(snWaitTimeout:) microseconds: 30 & USEC_PER_SEC data: d notify: @selector(snWaitDestroy:)]; change = YES; break; case SN_MONITOR_EVENT_CHANGED: /* XXX feedback changed? */ change = YES; break; case SN_MONITOR_EVENT_COMPLETED: case SN_MONITOR_EVENT_CANCELED: if ((d = [self waitFind: sn_startup_sequence_get_id(seq)])) { [d set_feedback: NO]; [mainLoop removeTimeout: self handler: @selector(snWaitTimeout:) data: d cancel: NO]; change = YES; } break; }; if (change) { [[AZScreen defaultScreen] setRootCursor]; } } @end /* callback */ static void sn_event_func(SnMonitorEvent *event, void *data) { [[AZStartupHandler defaultHandler] snEventFunc: event data: data]; } #endif